To pass the Lua function to the instance _lua in C + +

Source: Internet
Author: User
Tags anonymous data structures lua unique id

Problem

In Lua, because a function is also the first class value, there is a parameter that takes the function as another function, or a function as the return value of the function. This mechanism can be more flexible and concise in many places, such as:

Copy Code code as follows:

Table.sort (table [, comp])

The comp here requires a function to be passed in, and we'll probably have the following form when we call:

Copy Code code as follows:

Table.sort (T, comp)--Direct Write function name
Table.sort (T, Local_comp)--a local function
Table.sort (t, function (A, b) xxx end)--temporarily construct an anonymous function

The last of these is the most flexible way to construct an anonymous function at any time when needed. This is used in Lua's own environment, and naturally there is no problem. However, when we register some functions into the LUA environment in C + +, and these functions need to use function parameters, the problem comes out.

LUA itself does not support the introduction of the LUA function as a function parameter to C + +, regardless of whether the function you want to pass in is global, local, or anonymous (the nature of anonymity is also partial). In general, the only way we interact is not by passing in a function, but by a global function name. C + + saves this function name, and when it needs to recall Lua, it is found in the LUA global table (according to the function name) and then called. The situation is roughly as follows:

Copy Code code as follows:

function lua_func () XXX End
Cfunc (Lua_func)--wrong
Cfunc ("Lua_func")--right

Our script module is designed to use a large number of C + + functions that require callback functions. Obviously, creating a large number of global functions, first from the point of view of writing code, is very troublesome.

Solve

The way we ultimately need it is probably as follows:

Copy Code code as follows:

Cfunc (Lua_func)--OK
Cfunc (function () XXX end)--OK
Local xxx = function () XXX end
Cfunc (XXX)--OK

To solve this problem, my idea is to do some packing directly in the LUA layer. Because the C + + side only supports passing in a global function name (of course not necessarily global, depending on the actual situation, it may be in the other structure of the table), that is, a string, so my idea is to map the LUA function and a unique string.

Copy Code code as follows:

Function Wrap (FN)
Local id = generate_id ()
Local fn_s = "__CALLBACK_FN". Id
_g[fn_s] = fn
Return fn_s
End

The Wrap function, which maps a function to a string in the global table, is used:

Copy Code code as follows:

Cfunc (Wrap (function () xxx end))
Cfunc (const char *fn_name, XXX); --The prototype of Cfunc

Cfunc is a function of the C + + side registered with LUA, and its prototype is very modest, that is, to receive only one function name, a string, as previously mentioned, C + + to call this callback function, according to the string to find the corresponding function. When the scripting party calls, if you want to pass in an anonymous function, call the Wrap function to wrap it.

An improved

The above method has a very serious problem, after calling the Wrap function multiple times, it will cause the global table to swell. We need to find a way to clear the data that wrap has created after the callback has been completed. This work can of course be put into C + + to do, such as after each callback, set the global table. But this is obviously wrong, because it violates the design principles of the interface, the additional mechanism is added in Lua, and the responsibility is best to be negative by LUA. To solve this problem, you can use the metamethods mechanism of LUA. This mechanism allows the application layer to be notified when specific events occur within LUA. Here, we need to focus on the __call event.

In Lua, a value of __call Metamethod can be called as a function call. For example:

Copy Code code as follows:

AB (1, 2)

Here in this function invocation form, LUA will find out if AB has __call metamethod, and if so, call it. This fact implies that a table can also be invoked. An improved wrap function is as follows:

Copy Code code as follows:

Local function create_callback_table (FN, name)
Local T = {}
T.callback = fn
Setmetatable (t, {__call =--Attention __call
Function (func, ...)--in the case of T (XX), it will be invoked to
Func.callback (...)--Real callback
Del_callback (name)--callback complete, clear wrap established data
End})
Return T
End

Function Wrap (FN)
Local id = generate_func_id ()--produces a unique ID
Local fn_s = "_CALLBACK_FN". Id
_g[fn_s] = create_callback_table (FN, fn_s)--_g[fn_s] corresponds to a table
Return fn_s
End

In our C + + program, as usual, first from the _g to take out the object corresponding to the function name. Although this object is now a table. And then Lua_call.

Will the above code increase the unacceptable performance cost on the original basis? Although I have not done the actual test, it seems to me that excluding the cost of the meta table in Lua is a few more Lua function calls.

Finally, sigh, the table and metatable mechanism in LUA are very powerful. This power is not a powerful feature, but a combination of simple things that are powerful. The design idea behind it, really let people admire.

4.26.2011 Update

In the previous article, "Lua itself does not support the introduction of LUA functions as function parameters to C/S", which is strictly incorrect (commented by a netizen). Assuming the function cfun is registered by C/s + +, we can write the following code:

Copy Code code as follows:

Cfunc (print)--Incoming LUA function

But the problem is that we can't get this function out and save it on the C + + side. LUA provides a number of interfaces for taking Cfunc parameters, such as lual_checknumber (Encapsulation Lua_tonumber). But there is no interface similar to lual_checkfunction. The table in Lua has the same problem. The main reason for this is that the functions in Lua do not correspond directly to C + + data structures.

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.