The UserData in Lua

Source: Internet
Author: User

"The word starts here."

When I published the "Types and values in Lua" article, a reader left me a message saying, "You should summarize the function and UserData types in Lua." Now is the time to summarize. For function, I summarize in the "functions in Lua" article, and this article will take a closer look at the UserData in Lua. For the article, if you have any doubt, you can leave a message below the article, you can also follow my Sina Weibo interaction with me. Learn, I want to share, I look forward to your joining.

"What is UserData?" 】

What's UserData? The simple literal translation is the user data, if again the literary point, is called the user custom data. What good would it be to have the goods? First, let's imagine a scenario where you can define a struct in C, and when you define a struct in C, do you have any idea how to get Lua to represent the struct, that is, how Lua and C communicate, and how can lua properly access the struct? This is a practical and practical requirement. What do you do when you meet this demand? This time, the practical userdata will be able to work, so LUA provides a basic type of--userdata. UserData provides a primitive memory area that can be used to store anything. Also, UserData does not have any pre-defined actions in Lua. Let's take a look at how to use UserData.

The function Lua_newuserdata allocates a chunk of memory according to the specified size, presses the corresponding userdata into the stack, and finally returns the address of the memory block:

void *lua_newuserdata (lua_state *l, size_t size);

Below, the use of UserData is explained by a simple example.

Static struct studenttag{    char//  student name    char//  study number    int // Student Sex    int // student Age };

The definition of a student structure, followed by the operation, is carried out on the student structure, including setting the student's name, school number, gender and age.

Static int Student (lua_state *L) {    sizeof(struct  studenttag);     struct Studenttag *pstudent;     = (struct studenttag *) lua_newuserdata (L, ibytes);     return 1 // The new UserData is already on the stack. }

Create a new student structure, use the Lua_newuserdata function, after creation, the new UserData is on the stack and can be returned directly to Lua. Here's an example of setting a name and getting a name.

Static intGetName (Lua_state *L) {    structStudenttag *pstudent = (structStudenttag *) Lua_touserdata (L,1); Lual_argcheck (L, Pstudent! = NULL,1,"wrong Parameter"); Lua_pushstring (L, Pstudent-strName); return 1;}Static intSetName (Lua_state *L) {    //The first parameter is a UserData    structStudenttag *pstudent = (structStudenttag *) Lua_touserdata (L,1); Lual_argcheck (L, Pstudent! = NULL,1,"wrong Parameter"); //The second argument is a string    Const Char*pname = lual_checkstring (L,2); Lual_argcheck (L, PName! = NULL && PName! ="",2,"wrong Parameter"); Pstudent->strname =PName; return 0;}

In the GetName function, there is only one parameter, which is the UserData created using the student function, and then the C language, which takes the name out of the stack, and returns it to Lua.

In the SetName function, you need to pass in two parameters, the first parameter is UserData, the second parameter is the value that needs to be set, and then the direct assignment is good, easy to use, no very complicated steps, you feel it?

"Meta-table"

The code above has a very serious problem, why do you say so? I'll first post the LUA code for the previous example:

 require  " userdatademo1  "  local objstudent  = Student. new   () Student.setname (objstudent,   "  jelly want   " ) Student.setage (objstudent,  15  ) Local StrName  = Student.getname (objstudent) Local iage  =  Student.getage (objstudent) print (strName) print (iage)  

After calling student's new to get a student instance, the first parameter is the UserData that is obtained using the student function, which is the objstudent in the above code, when other functions of student are called later. On the side of the C module, we simply judge whether the incoming UserData is null, and there is no way to judge the incoming UserData parameters are obtained using the student function; If I pass a wrong userdata in, the program will continue to run, However, it is possible that memory is compromised. So how do we make sure our incoming UserData is the userdata we need? We need such a mechanism to ensure the legitimacy of the parameters.

One way to identify different types of userdata is to create a unique meta-table for each type (what is a meta-table?). )。 Whenever a userdata is created, it is marked with the corresponding meta-table. And whenever you get a userdata, check to see if it has the correct meta-table. Because the LUA code cannot alter the USERDATA's meta-table, there is no way to spoof the code.

To create a meta-table for each userdata, there is a place to store the new meta-table. In Lua, it is customary to register all new C types in the registry with a type name as key and a meta table as value. Because there is something else in the registry, you must carefully select the type name to avoid conflict with the key.

Some functions are provided in the LUA Auxiliary library to help implement what is said above, and the auxiliary library functions that can be used are:

int Const Char *tname); void Const Char *tname); void int Const Char *tname);

The Lual_newmetatable function creates a new table to use as a meta-table, pushes it to the top of the stack, and then associates the table with the specified name in the registry. The Lual_getmetatable function can retrieve the meta-table associated with the Tname in the registry. Lual_checkudata can check whether a userdata is at the specified position in the stack and whether it has a meta table that matches the given name, and if the object is not a userdata, or if it does not have the correct meta-table, an error is raised Otherwise it will return the address of the UserData. Now let's rewrite the example above:

int Luaopen_userdatademo2 (lua_state *L) {    //  Create a new meta-table    "  Student");     " Student " , Arrayfunc);     return 1 ;}

Creates a new meta-table that is the unique identifier for the UserData.

Static intStudent (Lua_state *L) {size_t ibytes=sizeof(structStudenttag); structStudenttag *pstudent; Pstudent= (structStudenttag *) Lua_newuserdata (L, ibytes); //set up a meta tableLual_getmetatable (L,"Student"); Lua_setmetatable (L,-2); return 1;//The new UserData is already on the stack.}

When creating the UserData, set the UserData's meta-table. When used, we can call Lual_checkudata to check the parameters.

Static int GetName (lua_state *L) {    struct studenttag *pstudent = (struct1"  Student");    Lua_pushstring (L, pstudent-strName);     return 1 ;}

When you write down the LUA statement:

Student.getage (Io.stdin)

Will throw such an exception error:

Bad argument #1'getage' (Student expected, got UserData)

Now, I think you should know how to use UserData easily. Next, something. Click here to download the full project engineering Userdatademo2.zip.

Object-oriented Access

With regard to Lua's object-oriented programming, I summarized in the article "Object-oriented programming in LUA" that if you are not familiar with object-oriented programming in Lua, you can read about object-oriented programming in Lua.

As you can see in the LUA code above, I have called the function in the following ways:

local strName = Student.getName(objStudent)

This kind of invocation is understandable, but from an object-oriented point of view, I am new to an object, this is a separate object, I should call this, in order to better understand AH.

local strName = objStudent:getName()

Right. This goes back to the question in the article "Object-oriented programming in Lua," because GetName, setname and so on are all defined in student, and in Objstudent objects, there is no definition of these functions. Still the old way, we need to set Objstudent's meta-table, set the __index field, when the corresponding function is not found in objstudent, go to student to find, before in the "object-oriented Programming in LUA" article, is also described in this approach. Come on, realize it.

intLuaopen_userdatademo3 (Lua_state *L) {    //Create a new meta-tableLual_newmetatable (L,"student_metatable"); //meta table. __index = Meta TableLua_pushvalue (L,-1); Lua_setfield (L,-2,"__index");    Lual_register (L, NULL, Arrayfunc_meta); Lual_register (L,"Student", Arrayfunc); return 1;}

In the above code, there are two places to pay special attention. The first thing to do is to set student.__index = Student, using lines 7th and 8 in the code above. Another area to be aware of is the special use of lual_register. At the first call to Lual_register, its second argument is null, so that Lual_register does not create any table for storing functions, but instead uses table at the top of the stack as the table for the stored function. Now the table at the top of the stack is the meta-table created by lual_newmetatable. In the code, the third parameter of the two Lual_register is different, and they are defined as follows:

Static structLual_reg arrayfunc[] ={    { "New", Student}, {null, NULL}};Static structLual_reg arrayfunc_meta[] ={    { "GetName", GetName}, {"SetName", SetName}, {"Getage", Getage}, {"Setage", Setage}, {"Getsex", Getsex}, {"Setsex", Setsex}, {"Getnum", Getnum}, {"Setnum", setnum}, {null, NULL}};

Final Call Lual_register (L, "Student", arrayfunc); The resulting Student table has only one function new, while the meta-table student_metatable has ARRAYFUNC_ All the methods contained in the meta array. I'm pasting the LUA code, and then I'll analyze the process in detail.

 require   "  Userdatademo3   " local  objstudent =< Span style= "COLOR: #000000" > Student.new () objstudent:setname (  "  jelly want   " ) Objstudent: Setage ( 15   local  strName = Objstudent:getname ()  local  iage = Objstudent:getage ()  print   (strName)  print  (iage) 
    1. Call require "Userdatademo3″ will get a student table, in which there is only one function--new;
    2. Call Student.new () will get a userdata of a student struct, the metatable of the UserData is student_metatable;
    3. Since there is no key in the UserData itself, there is no concept of the key in the table as in the UserData, and when Objstudent:setname is called, it goes to the student_metatable of the meta-table to find SetName, then complete the call;
    4. Since student itself is not set to the meta table student_metatable, when Student.setname (Objstudent, "Jelly think") is called, an error occurs. This is good, student itself is not an actual "student" object, just a template, using student direct call SetName error, fully conform to the semantics.

Of course, other predefined meta-methods can also be redefined, except that __index can be redefined. The implementation of the __tostring meta method is provided in the complete project engineering, click here to download the complete project Userdatademo3.zip.

Lightweight UserData

Why is there a lightweight userdata? What's this stuff? Professional point, called "Light UserData". The UserData I summarized earlier is called "Full UserData".

Lightweight UserData is a value that represents a C pointer (that is, void *). Because it is a value, you do not have to create it. To put a lightweight userdata into the stack, you just need to call lua_pushlightuserdata.

void lua_pushlightuserdata(lua_State *L, void *p);

Although the two userdata are similar in name, they are very different from each other. Lightweight UserData is not a buffer, just a pointer. It also has no meta-tables, just like numbers, where lightweight userdata are not managed by the garbage collector.

The real use of lightweight userdata is equality judgment. A complete UserData is an object that is only equal to itself. A lightweight userdata represents the value of a C pointer. Therefore, it is equal to all lightweight userdata that represent the same pointer. You can use the lightweight UserData to find C objects in Lua.

Now for the use of a lightweight userdata, I also remember in the "C module writing (2)" In the summary of the registration form? When it comes to the key of the registry, it is a good idea to use the UUID, and now use the lightweight userdata with static to implement the conflict-free key.

 'k'*"jellythink"); Lua_ Settable (L, lua_registryindex);

Because the address of a static variable is unique in a process, there is absolutely no problem with duplicate key.

 *) &key); Lua_gettable (L, lua_registryindex);

The UserData in Lua

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.