In Lua, you can interact with the C language code more efficiently and flexibly by customizing the type. Here's a simple and complete example to learn how to use UserData in Lua. It should be explained that the example is entirely from programming in Lua. Its function is to implement a LUA Boolean array with the C program to provide efficient execution of the program. See the code and critical comments below.
#include <lua.hpp>
#include <lauxlib.h>
#include <lualib.h>
#include <limits.h>
#define BITS_PER_WORD (char_bit * sizeof (int))
#define I_word (i) ((unsigned int) (i))/bits_per_word
#define I_BIT (i) (1 << (unsigned int) (i)%bits_per_word))
typedef struct NUMARRAY {
int size;
unsigned int values[1];
} Numarray;
extern "C" int newarray (lua_state* L)
{
//1. Check whether the first parameter is an integer. and whether the value of the parameter is greater than or equal to 1.
int n = lual_checkint (l,1);
Lual_argcheck (L, n >= 1, 1, "Invalid size.");
size_t nbytes = sizeof (Numarray) + I_word (n-1) * sizeof (int); The
//2. Parameter represents the number of bytes allocated by LUA for UserData. The assigned UserData object is also pressed into the stack.
numarray* a = (numarray*) lua_newuserdata (l,nbytes);
a->size = n;
for (int i = 0; i < I_word (n-1); ++i)
A->va Lues[i] = 0;
//Get Registry variable myarray, the value of this key is metatable.
lual_getmetatable (L, "myarray");
//Set the UserData meta table to the table associated with MyArray. The top element of the stack is also ejected.
lua_setmetatable (l,-2);
return 1;
}
extern "C" int setarray (lua_state* L)
{
//1. The first argument that Lua passes to the function must be UserData, and the Wenzu of the object must also be a table associated with myarray in the registry.
/Otherwise the function complains and terminates the program.
numarray* a = (numarray*) lual_checkudata (l,1, "myarray");
int index = lual_checkint (l,2)-1;
//2. Because any type of data can be a Boolean value, the use of any is used here only to ensure that there are 3 parameters.
Lual_checkany (l,3);
Lual_argcheck (l,a!= null,1, "' array ' expected.");
Lual_argcheck (l,0 <= index && Index < a->size,2, "index out of range.");
if (Lua_toboolean (l,3))
A->values[i_word ( Index)] |= i_bit (index);
Else
A->values[i_word (index)] &= ~i_ BIT (index);
return 0;
}
extern "C" int GetArray (lua_state* L)
{
numarray* a = (numarray*) lual_checkudata (l,1, "myarray");
int index = Lual_checkint (l,2)-1;
Lual_argcheck (L, a!= NULL, 1, "' array ' expected.");
Lual_argcheck (L, 0 <= index && Index < a->size,2, "index out of range");
Lua_pushboolean (L,a->values[i_word (Index)] & I_bit (index));
return 1;
}
extern "C" int getsize (lua_state* L)
{
numarray* a = (numarray*) lual_checkudata (l,1, "myarray");
Lual_argcheck (l,a!= null,1, "' array ' expected.");
Lua_pushinteger (l,a->size);
return 1;
}
extern "C" int array2string (lua_state* L)
{
numarray* a = (numarray*) lual_checkudata (l,1, "myarray");
Lua_pushfstring (L, "Array (%d)", a->size);
return 1;
}
Static Lual_reg Arraylib_f [] = {
{"New", NewArray},
{NULL, NULL}
};
Static Lual_reg Arraylib_m [] = {
{"Set", SetArray},
{"Get", GetArray},
{"Size", getsize},
{"__tostring", array2string},//print (a) when Lua calls the Meta method.
{NULL, NULL}
};
extern "C" __declspec (dllexport)
int Luaopen_testuserdata (lua_state* L)
{
1. Creates the meta table and assigns the meta table to the newly created UserData of the NewArray function. UserData also behaves as a table in Lua.
Thus, when calling an object function, you can determine whether the parameter UserData is legitimate by validating its metatable name.
Lual_newmetatable (L, "myarray");
Lua_pushvalue (l,-1);
2. In order to realize the invocation of the object, you need to point the __index field of the meta table to itself, and then register the function in the arraylib_m array to
Meta table, then calls based on these registration functions can be called in object-oriented form.
Lua_setfield will eject the table on top of the stack after execution.
Lua_setfield (l,-2, "__index");
Register these member functions with the Meta table to ensure that Lua is positioned to find the method. A null parameter means that the table at the top of the stack replaces the second argument.
Lual_register (l,null,arraylib_m);
Here only the registered factory method.
Lual_register (L, "Testuserdata", arraylib_f);
return 1;
}
The previous introduction of full Userdata,lua also provides another lightweight userdata (light UserData). In fact, lightweight userdata only represents the value of a C pointer, that is, (void*). Because it's just a value, you don't have to create it. If you need to put a lightweight userdata into the stack, call Lua_pushlightuserdata. The biggest difference between the full userdata and the light UserData is the equality judgment, which is just equal to the one in its own, while light userdata is represented as a C pointer, so It is equal to all light userdata that represent the same pointer. And then there's the light. UserData is not managed by the garbage collector and is used like a normal integer number.