Fflib fflua--c++ Embedding lua& extension LUA tool [turn]

Source: Internet
Author: User
Tags assert lua what interface

Summary:

In server development using C + +, scripting techniques are often used, and Lua is one of the best embedded scripts. The lightweight, compact and simple concept of Lua makes him more and more popular. I have also used Python to do embedded script, both have characteristics, about Python will write related articles, Python for me more like to write tools, my front some of the relevant algorithms are implemented in Python. Today is mainly about LUA-related development techniques. LUA has the following features:

  • LUA has the concept of virtual machines, which are all implemented in standard C, compile and install without any libraries, and, more surprisingly, the entire LUA implementation code is not much, can be directly inherited into the project, and the compilation time of the project has little impact
  • LUA's virtual machines are thread-safe, and the thread-safety level here refers to the STL's thread-safety level, where a LUA virtual machine is secured by one thread, and multiple LUA virtual machines are accessed separately by multiple threads, and it is unsafe for a LUA virtual machine to be accessed by multiple threads.
  • The concept of Lua is very small, and the data structure is only table, so when using LUA as a project configuration file, even without programming skills can be quickly prepared.
  • Lua has no native object and no class keyword, which guarantees a simple concept, but can still be programmed using LUA object-oriented programming.
  • Although LUA is small and supports more advanced programming paradigms, anonymous functions and closures in Lua can make code more elegant and efficient, and if someone uses a C + + compiler that is old-fashioned and does not support c++11, then quickly feel the anonymous functions and closures of LUA.
  • Lua is one of the most efficient embedded scripts (if not the most, the evidence now shows the most).
  • Lua's garbage collection can also make C + + programs profitable, which is one of the key advantages of C + + scripting technology.
  • Lua's embedding is very easy, CAPI is relatively concise, and the documentation is clear, and of course Lua's CAPI needs to master the concept of a unique stack in Lua, but it's still simple enough.
  • The expansion of Lua is also very easy, it involves some techniques to import C + + as objects, functions into LUA, and if pure use of Lua CAPI will be a little cumbersome, fortunately some third-party libraries simplify these operations, and Fflua is definitely one of the best.

Embedding Lua:

Embedded in the Lua script, the Lua script must be loaded into the LUA virtual machine, and the concept in Lua is called the dofile operation in Dofile,fflua, since LUA files may be centrally placed in a directory, Fflua also provides an interface for setting up the Lua script directory:

int  add_package_path (const string& str_) int  load_file (const string& file_name_) throw (lua_exception _t)

Load_file is the execution of the dofile operation, if there is an error, throw the exception object, you can use exception to refer to the target object using the What interface output code error TRACEBACK.

When embedding Lua, the simplest scenario is to use the Lua script as a configuration, then you need to get the variables in the Lua script and set the LUA variable, Fflua encapsulates two interfaces for this operation. Lua is a dynamic language, and a variable can be assigned to any type supported by LUA, but C + + is strongly typed, so two interfaces are generic:

    template<typenamet>    int  get_global_variable (conststring& field_name_, t& ret_);    template<typenamet>    int  get_global_variable (constchar* field_name_, t& ret_);

Sometimes it is necessary to execute some LUA statements directly, and LUA has the concept of dostring, which encapsulates a separate interface run_string in Fflua:

void Run_string (constchar* str_) throw (lua_exception_t)

The most common scenario when embedding Lua is to call functions in Lua, where LUA functions are more flexible than C + + and can support any number of parameters, which are automatically set to nil if not assigned, and can return multiple return values. Anyway, from a C + + perspective, when you embed Lua calling LUA functions, you always want LUA to be used as well as C + +, and you don't want to complicate the process of calling function arguments, such as C + + data into data that LUA can handle, which is uninteresting and error prone. It is precisely what Fflua needs to do, encapsulating the operation of the LUA function, making the assignment parameter, calling the function, and receiving the details of the return value transparent, as the C + + caller calls the normal C + + function. Use the call interface to invoke the LUA function in Fflua:

void Call (constchar* func_name_) throw (lua_exception_t)

The exception information records the Traceback when an error is called.

In fact, Fflua overloads the 9 call functions, since the LUA function that calls 9 parameters is automatically adapted.

Template<typename ret>     RET Call (const char* func_name_) throw (lua_exception_t);    ......    Template<typename RET, TypeName ARG1, TypeName ARG2, TypeName ARG3, TypeName ARG4,             TypeName ARG5, TypeName ARG6, Ty Pename ARG7, TypeName ARG8, TypeName arg9>    RET Call (const char* func_name_, ARG1 arg1_, ARG2 arg2_, ARG3 arg3_,
   
    arg4 arg4_, ARG5 arg5_, ARG6 arg6_, ARG7 arg7_,             ARG8 arg8_, ARG9 arg9_) throw (lua_exception_t);
   

What you need to mention is:

    • The parameters of the call interface are generic and are automatically converted to LUA using the paradigm traits mechanism and push into the LUA stack
    • The return value of the call interface is also normal, which requires that the type of the return value must be provided when calling is used, and what if the LUA function does not return a value? There is a feature in Lua where the Boolean value of nil and false is false, so when the LUA function returns NULL, you can still receive arguments using the bool type, except that the caller ignores the return value.
    • Call supports only one return value, although LUA can return more than one value, but calls ignores the other return values, and is also intended to be as likely to invoke C + + functions as to return multiple values, which can be returned with a table.

Extending LUA:

This is also a very important operation, and embedding Lua always accompanies the extended Lua. To manipulate objects or functions in C + +, LUA must first register the interfaces of C + + with Lua. Lua CAPI provides a series of interfaces to do this, but the operation on the stack is always a bit of a headache, and Fflua greatly simplifies the operation of registering C + + objects and interfaces, which is one of the simplest ways to register (if not the most). Let's start by sorting out which registration actions are required:

    • C + + static functions are registered as global functions in Lua, so calling C + + functions in Lua is like calling C + + global functions
    • C + + objects are registered as objects in Lua, and you can create C + + objects in Lua via the new interface
    • The properties in a C + + class that are registered to the Lua,lua Access object are like accessing properties in a table.
    • A function in a C + + class is registered in Lua, and LUA calls its interface as if it were a call to an interface in Talbe.

The Fflua provides a paradigm interface that is suitable for registering C + + Related data:

Template<typename t>void  Fflua_t::reg (T a) {    a (this->get_lua_state ());}

In this way, to register the LUA operation, you only need to provide a copy function, so that you can register all the C + + data in bulk, of course, Fflua provides a tool class to generate the copy function should complete the registration operation:

Template<typename Class_type = op_tool_t, typename ctor_type = void () >class fflua_register_t{public:    fflua_ register_t (lua_state* Ls_): M_ls (Ls_) {}    fflua_register_t (lua_state* ls_, const string& class_name_, String Inherit_name_ = "");    Template<typename func_type>    fflua_register_t& def (func_type FUNC, const string& s_)    {        Fflua_register_router_t<func_type>::call (This, FUNC, s_);        return *this;}    ;

All of the registration operations mentioned earlier, like Lua, can be done using the DEF operation. Examples are as follows:

//! Register subclasses, ctor (int) as constructors, foo_t as type name, base_t as inherited base class name    fflua_register_t<foo_t, ctor (int) > (ls, "foo_t", "base_t" )                . def (&foo_t::p rint, "print")        a function of the subclass//!                . def (&foo_t::a, "a");               //! The fields of the subclass

In particular, inheritance in C + + can be maintained in the register to LUA so that the interface of the base class is registered, and the subclass does not need to be re-registered.

Advanced Features:

From the above, perhaps you have already understood the design principle of Fflua, that is, when writing C + + code, I want to use Lua just like C + + local code, while in LUA operation of C + + data and interfaces, but also want to use the C + + is exactly the same as table. This can greatly reduce the work of the program development, so that the energy more amplification design and logic. So how does Lua work like c++,c++ to be like Lua? We know that after all, the difference is very far, we just need to encapsulate the common operation is always, uncommon operation is special treatment. Common operations are:

    • C + + calls the LUA function, Fflua has encapsulated the call function, guaranteeing that calling Lua functions is as convenient as calling a local C + + function
    • C + + registers interfaces and objects into LUA, and the operands in Lua are as straightforward as manipulating table.
    • In addition to custom objects in C + +, STL is the most used, and C + + wants Lua to be able to receive STL parameters, or to return STL data structures
    • LUA has only table data structures, and LUA expects the data structure of C + + parameters to support table, and LUA can directly use table as the return value.
    • C + + pointers need to be passed into Lua, and hopefully some operations, LUA can use C + + object pointers as return values

The above two have been introduced, the latter three Fflua is also to give perfect support. With the generic C + + package, the C + + STL can be transformed perfectly into luatable, and when Lua returns to table, the Lua table is automatically converted to C + + STL based on the return value type. As long as the registered C + + objects in the Fflua, they can be assigned to LUA as parameters, even in Lua. When I tell the above features, it is in the premise of ensuring type safety. Important types of checks are:

    • When STL is converted to luatable, the types in the STL must be LUA-supported, including basic types and already registered C + + object pointers. And STL can be nested use, such as vector<list<int>; don't be surprised, this is supported, regardless of how many layers are nested, is supported, using the C + + template recursive mechanism, this feature has been perfectly supported. Vector, list, and set are converted to the array pattern of table, and key starts from 1. The map type is automatically adapted to a table dictionary.
    • The table in Lua can be converted to C + + STL as the return value, and the conversion is exactly the same as the top, but there is a limitation, because the STL type of C + + must be unique, such as the return value of vector<int> requires that all table values in Lua are int. Otherwise Fflua will return an error and prompt for type conversion failure
    • Whether a C + + object pointer is used in a dead call to Lua or a C + + object pointer is returned in LUA, the object must be LUA-aware, which is already registered, or Fflua will prompt the conversion type to fail.

About overloading:

For overloaded Lua, you can use the internal reload of LUA, or you can destroy the Fflua object, create one first, the overhead of creating Fflua objects, and the overhead of creating a LUA virtual machine without additional overhead.

Summarize:

    • Fflua is a class library that simplifies C + + embedding bound Lua scripts
    • Fflua has only three header files and does not rely on any class libraries other than LUA, developers can easily use Fflua
    • Fflua support for common STL data structures
    • Fflua even if you have so many features, still maintain a light weight, as long as the use of C + +, as long as the use of Lua,fflua code can be very clear to see its implementation, when you understand its internal implementation, you will find that Fflua has done a minimalist, pattern template expanded code with your own native Lua CAPI was written just as directly.
    • Fflua's Open source code:Https://github.com/fanchy/fflua

Complete sample code for C + +:

#include <iostream> #include <string> #include <assert.h>using namespace std; #include "lua/fflua.h" Using namespace Ff;class base_t{public:base_t (): V (789) {} void Dump () {printf ("in%s a:%d\n", __function_    _, V); } int v;};     Class Foo_t:public base_t{public:foo_t (int b): A (b) {printf ("in%s b:%d this=%p\n", __function__, B, this);    } ~foo_t () {printf ("in%s\n", __function__);    } void Print (int64_t A, base_t* p) const {printf ("in foo_t::p rint a:%ld p:%p\n", (Long) A, p);    } static void Dumy () {printf ("in%s\n", __function__); } int a;};/ /! Lua Talbe can be automatically converted to STL objects void Dumy (map<string, string> ret, vector<int> A, list<string> B, set<int64_t    > C) {printf ("in%s begin------------\ n", __function__);  For (map<string, string>::iterator it = Ret.begin (); It! = Ret.end (); ++it) {printf ("map:%s, val:%s:\n", It->first.c_str (), It->second.c_str()); } printf ("In%s end------------\ n", __function__);}   static void Lua_reg (lua_state* ls) {//! registers the base class function, ctor () is the type of the constructor fflua_register_t<base_t, ctor () > (LS, "base_t") //! Register constructor. def (&base_t::d UMP, "dump")//!          Registers the function of the base class. def (&base_t::v, "V"); //! Register the properties of the base class//!                Register subclasses, ctor (int) as constructors, foo_t as type name, base_t as inherited base class name fflua_register_t<foo_t, ctor (int) > (ls, "foo_t", "base_t") . def (&foo_t::p rint, "print")//!               The function of the subclass. Def (&foo_t::a, "a"); //!                The subclass of the field fflua_register_t<> (LS). def (&dumy, "dumy"); //!    Register static function}int main (int argc, char* argv[]) {fflua_t Fflua;                try {//! Register C + + objects into Lua fflua.reg (LUA_REG); //!        Load Lua file Fflua.add_package_path ("./");                Fflua.load_file ("Test.lua"); //!        Gets the global variable int var = 0; ASSERT (0 = = fflua.get_global_variable ("Test_var", Var)); //!        Set global variable assert (0 = = fflua.set_global_variable ("Test_var", ++var)); //! Executes the LUA statement fflua.run_string ("Print (\" EXE run_string!!                \")"); //!        Call Lua function, base type as parameter int32_t arg1 = 1;        float arg2 = 2;        Double arg3 = 3;        String arg4 = "4";                Fflua.call<bool> ("Test_func", Arg1, Arg2, Arg3, ARG4); //!        Call LUA function, STL type as parameter, automatically convert to Lua talbe vector<int> VEC;        Vec.push_back (100);         List<float> lt;        Lt.push_back (99.99);         Set<string> St;        St.insert ("Ohnice");    Map<string, Int> MP;        mp["key"] = 200;                Fflua.call<string> ("Test_stl", Vec, Lt, St, MP); //!        Call Lua function to return talbe, automatically convert to STL structure VEC = fflua.call<vector<int> > ("Test_return_stl_vector");        lt = fflua.call<list<float> > ("test_return_stl_list");       st = fflua.call<set<string> > ("Test_return_stl_set"); MP = fflua.call<map<string, int> > ("Test_return_stl_map"); //!        Call Lua function, C + + object as parameter, foo_t must be registered foo_t* foo_ptr = new foo_t (456);                Fflua.call<bool> ("Test_object", foo_ptr); //!        Call Lua function, C + + object as return value, foo_t must be registered assert (Foo_ptr = = fflua.call<foo_t*> ("Test_ret_object", foo_ptr)); //!        Call the LUA function, the C + + object as the return value, automatically converted to the base class base_t* base_ptr = Fflua.call<base_t*> ("Test_ret_base_object", foo_ptr);     ASSERT (Base_ptr = = foo_ptr);    } catch (exception& e) {printf ("exception:%s\n", E.what ()); } return 0;}
The complete LUA sample code:
Test_var = 99function dump_table (TB, str) if nil = = str then str = "" "End for K, V in pairs (TB) do print (s    TR, K, v) endend--Test call Luafunction test_func (arg1, arg2, Arg3, Arg4) print ("In Test_func:", Arg1, Arg2, Arg3, ARG4) MP = {["k"] = "V"} VC = {4,5,6} lt = {*.} st = {7,8,9} dumy (MP, VC, lt, St) end--accept STL parameter function Test_st  L (VEC, LT, St, MP) print ("--------------dump_table begin----------------") dump_table (VEC, "Vec") dump_table (LT,  "LT") Dump_table (St, "St") dump_table (MP, "MP") print ("--------------dump_table End----------------") return "OK" end--returns the STL parameter function Test_return_stl_vector () return {1,2,3,4}endfunction test_return_stl_list () return {1, 2, 3,4}endfunction Test_return_stl_set () return {1,2,3,4}endfunction Test_return_stl_map () return {["key"] = 12 4}end--Test accepts C + + object function Test_object (foo_obj)--Test Fabric base = Base_t:new ()--each object has a Get_pointer get pointer print ("Base ptr:", base:get_pOinter ())--Test C + + object functions foo_obj:print (12333, Base) Base:delete ()--base class functions Foo_obj:dump ()--Test C + + object properties Print ("Foo property", foo_obj.a) print ("base", FOO_OBJ.V) end--Test returns C + + Object function Test_ret_object (foo_obj) r Eturn foo_objend--Test returns C + + Object function Test_ret_base_object (foo_obj) return foo_objend

Fflib fflua--c++ Embedding lua& extension LUA tool [turn]

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.