Quick mastering of Lua 5.3--techniques for writing C library functions available to LUA (2)

Source: Internet
Author: User

Q: What is "Registry"?

A: Sometimes we need to use some non-local variables in our program. In c we can use global variables or static variables, and in the process of writing C libraries for Lua, using variables of the above type is not a good way. First, the values of LUA cannot be stored in these variables. Second, these variables are likely to cause unintended results if they are used in multiple LUA state machines.
An alternative is to store these values in the global variables of LUA. This approach solves the two problems mentioned above, and LUA global variables can store any LUA values, while each LUA state machine has its own set of global variables. But this is still not the best way, because it is the global variable of LUA, the LUA program can arbitrarily modify the value of the variable, which is likely to affect the function in the C library when using these variables.
To further avoid this, LUA provides a special "table" that can be used arbitrarily by C code. But for LUA code, access is forbidden. This special "table" is "registry",

Q: What is "Pseudo-index"?

A: "Pseudo-index" is similar to a normal index in a virtual stack, but its difference from a normal index is that although it is used by a virtual stack, its corresponding value is not stored in the virtual stack.
LUA_REGISTRYINDEXis a "pseudo-index", defined in "Lua.h", it is used to access "registry" through the virtual stack (but "registry" is not actually stored in the virtual stack), used in accordance with the normal index in the virtual stack usage.
For example, you can get the value of an element indexed as "Key" in "Registry" in the following way,

lua_pushstring"Key");lua_gettable(L, LUA_REGISTRYINDEX);
Q: How do I guarantee that the index in "registry" is unique?

A: "Registry" is an ordinary Lua "table", so you can access nil its elements as "key" using a non-value as a "table". However, since all C libraries share the same "registry", you must be aware of what values to use as "key" to not cause naming conflicts.
One way to prevent naming collisions is to use the address of the "static" variable as "key" so that the C linker will ensure that the address is unique across all libraries.
In the "MYLIB.C" file ( lua_pushlightuserdata a value representing the C pointer is placed in the virtual stack, which is described in detail later):

#include <stdio.h>#include <string.h>#include <lua.h>#include <lauxlib.h>#include <lualib.h>Static intL_test_registry (lua_state *l) {The //"key" variable stores what value is not important, because it uses its own address.     Static Const CharKey =' K ';Static Const CharKey1 =' K ';intMy_number =0; Lua_pushlightuserdata (L, (void*) &key);//Put "key" into the stack. Lua_pushnumber (L,9);//Put "value" into the stack. Lua_settable (L, Lua_registryindex);//"registry[key] = value".     //Different "key", Operation "Registry" in different elements. Lua_pushlightuserdata (L, (void*) &key1); Lua_pushnumber (L,Ten); Lua_settable (L, Lua_registryindex);//The Same "key", Operation "Registry" in the same element. Lua_pushlightuserdata (L, (void*) &key); Lua_pushnumber (L, One);    Lua_settable (L, Lua_registryindex); Lua_pushlightuserdata (L, (void*) &key);//Put "key" into the stack. Lua_gettable (L, Lua_registryindex);//"Registry[key]". My_number = Lua_tonumber (L,-1);//Get the result of virtual stack top.     printf("%d\n", My_number);// OneLua_pushlightuserdata (L, (void*) &key1);    Lua_gettable (L, Lua_registryindex); My_number = Lua_tonumber (L,-1);printf("%d\n", My_number);//Ten    return 0;//no return value. }Static Const structLual_reg mylib[] = {{"My_test_registry", l_test_registry}, {null, NULL}};extern intLuaopen_mylib (lua_state* L) {lual_newlib (L, mylib);return 1;}

Compile "MYLIB.C" as a dynamic connection library.

prompt> gcc mylib.c -fPIC -shared -o mylib.so -Wallprompt> lsmylib.c    mylib.so    a.lua

In the "A.lua" file:

localrequire"mylib"mylib.my_test_registry()--[[ results: 1110]]

Of course you can also use the string as "key" for "registry", as long as you guarantee that these strings are unique. The string "key" is useful when you plan to allow other independent libraries to access your data (because other independent libraries can clearly know the name of "key").
Finally, do not use numeric values as "key" for "registry" because they are intended for use by the "reference system".

Q: What is "reference system"?

A: "Reference system" consists of a pair of functions defined in the secondary library. With them, you can freely access data in "registry" without worrying about how to create a unique "key".

/* Generates a unique"Key", stack the value of the top of the stack as"Value", * The index from the virtual stack"T"Office to obtain"Table", and then do the equivalent"Table[key] = value"The operation. * function returns the generated"Key"。 * IF"Value"For"nil", it does not generate"Key", and the function returns"Lua_refnil"。 * Lua also defines the"Lua_noref", it represents a"Lual_ref"Any value that is returned is a different value. */intLual_ref (Lua_state *l,intt);/* index from the virtual stack"T"Office to obtain"Table", and then do the equivalent"table[ref] = nil"The operation. *"ref"It is also released (can be used again for"Lual_ref"Use). * IF"ref"Is"Lua_noref"Or"Lua_refnil", the function does not take any action. */void Lual_unref (Lua_state *l,intTintREF);

luaL_refThe "key" returned is called "reference".

Static intL_test_registry (lua_state *l) {int ref=0,value=0; Lua_pushinteger (L,9);//data into the stack.     //Save the data to "registry" and get the "reference" corresponding to the data.     ref= Lual_ref (L, Lua_registryindex);//Get the data corresponding to "reference" from "registry" and put it into the stack. Lua_rawgeti (L, Lua_registryindex,ref);value= Lua_tointeger (L,-1);//Get the data at the top of the stack. printf"%d\n",value);//9Lual_unref (L, Lua_registryindex,ref);//release "Reference".     return 0;}
Q: How to Implement "Closure" in C library function?

A: "Registry" provides a reasonably effective way to implement global variables for C library functions, while "Closure" will provide a reasonable and effective way to implement static variables for C library functions.
Similar to "Closure" in Lua, you can bind multiple "upvalue" for C library functions, and each "Upvalue" can store a LUA value. Then, when this "Closure" of the C library function is called, it is free to access its "upvalues" (Accessed through "pseudo-indices").

/* 创建一个C中的"Closure",将栈顶的"n"个值作为其"upvalues"。 * 弹出栈顶作为"upvalues"的"n"个值,最后将"Closure"*/*Lint n);// 返回当前运行的函数的第"i"个"upvalue"的"pseudo-indice"int lua_upvalueindex(int i);

In the following example, we will re-implement in the C library function newCounter (what is "Closures" before quickly mastering the Lua 5.3--function?). "Partially implemented using LUA code).
In the "MYLIB.C" file:

#include <stdio.h>#include <string.h>#include <lua.h>#include <lauxlib.h>#include <lualib.h>part of the function code for the//"Closure". Static intCounter (lua_state *l) {//Get the first "Upvalue" of "Closure".     Doubleval = Lua_tonumber (L, Lua_upvalueindex (1));/ * Add the "Upvalue" to 1 and then into the stack.     * (There is no actual "upvalue" update of "Closure") * This value will be the return value of "Closure". */Lua_pushnumber (L, ++val);/ * Copy the value of the new "Upvalue" and then into the stack.     * (because "lua_replace" below will eject this value) * This value will be used to actually update the "Upvalue" value of "Closure". */Lua_pushvalue (L,-1);/ * get "upvalue" for "Closure" and actually update it. * (also pops up the top of the stack to update the value of "Upvalue") */Lua_replace (L, Lua_upvalueindex (1));return 1;//Returns the most recent "Upvalue" value. }//Create a "Closure" in C. Static intL_newcounter (lua_state *l) {lua_pushnumber (L,0);//"Upvalue" into the stack with an initial value of 0.     //"counter" function as part of the function code of "Closure", it has a "upvalue". Lua_pushcclosure (L, &counter,1);return 1;//Returns the created "Closure" as the return value. }Static Const structLual_reg mylib[] = {{"My_newcounter", l_newcounter}, {null, NULL}};extern intLuaopen_mylib (lua_state* L) {lual_newlib (L, mylib);return 1;}

Compile "MYLIB.C" as a dynamic connection library.

prompt> gcc mylib.c -fPIC -shared -o mylib.so -Wallprompt> lsmylib.c    mylib.so    a.lua

In the "A.lua" file:

localrequire"mylib"newCounter1 = mylib.my_newCounter()print(newCounter1())    --> 1.0print(newCounter1())    --> 2.0newCounter2 = mylib.my_newCounter()print(newCounter2())    --> 1.0print(newCounter1())    --> 3.0
Additional:

1. Most functions in the Lua API can accept "Pseudo-index", except for some functions that manipulate the virtual stack itself, for example lua_remove , lua_insert etc.
2, when using the string as "registry" "Key", some good habits can avoid "key" conflict. For example, use the name of the library as a prefix, or use the Universal unique identifier (UUID). Many systems have specialized tools to produce "UUID", such as "Uuidgen" under Linux systems.
3, in fact, "reference system" can be applied to any "table", but their typical application is in "registry".
4, you can use the same function code, binding different "upvalues", thus creating a different "Closures". The same is true of "Closure" in the C library function.
5, C in the "Closure" and Lua in the "Closure" difference is that C "Closure" Can not share "upvalues", each "Closure" has its own independent "upvalues". However, we can set the "upvalues" of Different "Closure" to point to the same "table" so that this "table" becomes a place where all "Closure" share data.

Quick mastering of Lua 5.3--techniques for writing C library functions available to LUA (2)

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.