加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

LuaPlus官方文档

发布时间:2020-12-14 22:22:20 所属栏目:大数据 来源:网络整理
导读:LuaPlus for Lua 5.1 Distribution Build 1100+ (May 24,2008) Enhancements to Core Lua Functionality http://luaplus.org/ Author: Joshua Jensen (jjensen@workspacewhiz.com) Overview The LuaPlus distribution contains some modifications to the co

LuaPlus for Lua 5.1 Distribution
Build 1100+ (May 24,2008)

Enhancements to Core Lua Functionality

http://luaplus.org/

Author: Joshua Jensen (jjensen@workspacewhiz.com)

Overview

The LuaPlus distribution contains some modifications to the core Lua code base.? As such,it is not an official distribution of Lua 5.1 (which may be found at http://www.lua.org/),nor does it intend to represent itself as one.? Most modifications are superficial,but some,such as the wide character string type,end up touching a great deal of source files.? Any references to Lua in this document refer specifically to the modified Lua code contained herein,unless otherwise stated.

The LuaPlus distribution provides the following functionality.

  • All the power of the core Lua 5.1 work distribution.
  • An easy to use C++ interface:
    • The C++ interface,described below,masks many of the intricacies of core Lua's underlying low-level C API.? In particular,stack management is mostly ignored.? Other useful helper classes,such as management of ref'ed objects or the stack,table traversal,and table lookups are provided,dramatically simplifying the application code.
    • Simplified function calling convention.? Inspired by,to a limited degree,Python's use of tuples in its C API,the new function calling convention masks the stack pushing and popping associated with the low-level calling convention.
    • A newly added function calling convention enables C++ to call Lua functions as if they were regular C++ functions.? This goes a long way to simplifying Lua for C++ users.
    • A transparent C++ functor implementation is in place,allowing function callbacks to be global or static (as they are now),class member functions,or class member virtual functions.
    • Direct registering of C++ functions with LuaPlus.? The registered C++ functions do not need to conform to a standard callback declaration.
    • .NET wrapper.? The .NET version of LuaPlus opens up LuaPlus's features to any .NET based language.? This includes C#,Visual Basic,Python,Perl,and others.? The Managed C++ version of LuaPlus is nearly identical to its regular C++ counterpart,so transitioning is easy.
    • Serialization of Lua tables.? Lua is a boon for data management.? With a much simpler syntax than XML,while providing equivalent and better data description facilities,a way is needed to write table data in text form.? LuaPlus offers this facility,and it does it in such a way that no Lua internal state is changed.
    • Win32 DLL and LIB formats.? Through the DLL version,a module plug-in system is in place.
  • Extra Tools:
    • Debugger.? The Remote Lua Debugger all but eliminates the need to litter print() statements throughout script code.? It offers a view of the call stack,local variables,watch variables,syntax highlighting,has Visual C++ debugger style keystrokes,and much more.
    • Visual C++ watch add-in to monitor data types.? When manipulating a LuaObject (one of the classes provided by the C++ interface),Visual C++ 6 and Visual Studio .NET show the contents of the LuaObject in the watch window.? The LuaWatchAddin makes no distinction between stack objects,ref'ed objects,up-values,or other indices.? In addition,if the index being shown is out of range,the LuaWatchAddin represents that.
    • The Visual Studio .NET LuaPlus Debugger plug-in allows display of the?Lua tables in tree form,local Lua variables,and the current Lua callstack.? Stepping through Lua code in the VS .NET environment is not possible at this time,but the Remote Lua Debugger may still be used.
  • Lua Core Enhancements:
    • 16-bit wide character string support.
      • Tight integration of the extra string type was necessarily built into the code base.? Any reference to LUA_TSTRING in the Lua core code base was supplemented with an equivalent wide character LUA_TWSTRING.
      • Direct support for opening Unicode files available.
    • Ref'ed objects are treated no differently than a stack object.? Rather than dealing with low-level lua_getref() calls everywhere to load the ref'ed object onto the stack,the user can just "use" the object.? No special management is needed.

Visual Studio Watch Add-in

The LuaPlus Visual Studio LuaWatchAddin provides facilities whereby the Watch window will show the contents of a LuaObject,LuaTableIterator,LuaStackObject,LuaStackTableIterator,or TString (when stepping inside Lua internals).? The LuaWatchAddin does not expand Lua tables,but an additional add-in does.

  1. Copy LuaPlus/Bin/LuaWatchAddin.dll to Program Files/Microsoft Visual Studio .NET/Common7/IDE.
  2. Add the following lines to the bottom of Program Files/Microsoft Visual Studio .NET/Common7/Packages/Debugger/autoexp.dat:
    ; LuaPlus
    LuaPlus::LuaObject=$ADDIN(LuaWatchAddin.dll,AddIn_LuaObject)
    LuaPlus::LuaStackObject=$ADDIN(LuaWatchAddin.dll,AddIn_LuaStackObject)
    LuaPlus::LuaStackTableIterator=$ADDIN(LuaWatchAddin.dll,AddIn_LuaStackTableIterator)
    LuaPlus::LuaTableIterator=$ADDIN(LuaWatchAddin.dll,AddIn_LuaTableIterator)
    TString=$ADDIN(LuaWatchAddin.dll,AddIn_TString)
  3. Start debugging.

LuaPlus::LuaObjects,LuaPlus::StackObjects,LuaPlus::LuaTableIterators,LuaPlus::StackTableIterators and TStrings will expand in the watch window.

The LuaWatchAddin does not provide expansion for Lua tables,although the LuaPlus Debugger Add-in does.

Visual Studio .NET ManagedLuaPlus Watch Support

The ManagedLuaPlus Watch window support currently only works for LuaObject.

  1. Add the following lines to the bottom of Program Files/Microsoft Visual Studio .NET/Common7/Packages/Debugger/mcee_cs.dat:
    ; LuaPlus
    <ManagedLuaPlus.LuaObject>=<WatchType>
  2. Start debugging.

LuaPlus Visual Studio .NET Debugger Add-in

The LuaPlus Visual Studio .NET Debugger add-in allows viewing of Lua tables in a tree fashion.? Currently,there is no installer for this.

To manually install:

  1. Run:

    regsvr32 c:/LuaPlus/Bin/LuaPlusDebuggerAddin/LuaPlusDebuggerControls.dll
    regsvr32 c:/LuaPlus/Bin/LuaPlusDebuggerAddin/LuaPlusDebuggerAddin.dll
  2. Launch Visual Studio .NET.
  3. Start a debug session.
  4. Go to Tools->LuaPlus Watch Window.
  5. Dock the newly created window.

Technical Reference for the non-.NET library

Namespace: LuaPlus

All LuaPlus functionality is encapsulated in the LuaPlus namespace.? Any references to LuaPlus classes and types in this documentation assume the LuaPlus:: qualifier.

LuaPlus is an experimental C++ wrapper,and as such,there are sometimes multiple techniques for accomplishing the same result.? Usually,the multiple techniques need to stay around,as some of the more advanced ones employ C++ templates and are not conducive to implementation in Managed C++.

Namespace: ManagedLuaPlus

All LuaPlus.NET functionality is encapsulated in the ManagedLuaPlus namespace.? Any references to LuaPlus classes and types in this documentation assume the ManagedLuaPlus. qualifier.? For the sake of this document,C# will be used as the language accessing ManagedLuaPlus functionality.

Class: LuaState

LuaState is the C++ form of a lua_State.? Most C functions that accessed a lua_State are inlined functions in LuaState.? As far as efficiency goes,LuaState is equally as fast as the C low-level counterparts for most operations.

LuaPlus is set up to work in DLL or LIB form,therefore,special functions are provided for creating and destroying LuaState objects.? It is not possible to new a LuaState object,because it is necessary to ensure all allocation and deallocation is done within the same memory management system.? It is also not possible to call the core Lua lua_open() function and use a lua_State pointer from it.

Creating a LuaState Instance

Unmanaged

The static function LuaState::Create() is used to create a LuaState instance.? The Create() function provides the ability to initialize the Lua standard library,which consists of the auxiliary,base,debugging,I/O,math,ANSI string,wide string,and table libraries.? If the application is using LuaPlus strictly for data purposes,the standard library should probably not be initialized.

An alternate approach to creating and destroying a LuaState object is shown below,in the LuaStateAuto/Owner class.

LuaState* state = LuaState::Create();
Managed

A LuaState object is created no differently than any other .NET object.

LuaState state = new LuaState();

Currently,the majority of the Lua standard library is initialized per LuaState,too,and table libraries.

Creating a LuaState Thread Instance

Unmanaged To add another state,typically for coroutine purposes,to an existing LuaState instance,use the LuaState::CreateThread() static function.
LuaObject threadObj = LuaState::CreateThread(state);
Managed Not possible at this time.

Destroying a LuaState Instance

Unmanaged Calling the LuaState::Destroy() function runs all final garbage collection processes and frees any memory associated with the LuaState object.
LuaState::Destroy(state);
Managed No explicit destruction of a LuaState object is needed.? The .NET garbage collector will kick in and take care of clean up.

Changing a lua_State Pointer to a LuaState Instance (Unmanaged Only)

A special function called LuaState::CastState() exists for purposes of changing an underlying lua_State* to a LuaState*.? Note that CastState() can only be used if the lua_State pointer was originally from a LuaState::Create() call.? This separation may occur with certain Lua callbacks.

LuaState* castedState = LuaState::CastState(regular_lua_State);

Loading and Executing Lua Script Code from Disk

DoFile(const char* fileName) is used to load and execute scripts from disk.? It mirrors lua_dofile() in functionality.? UCS-2 files are handled automatically as are standard 8-bit files.

There is an alternate version of DoFile() taking a second parameter,a LuaObject describing the function environment for the block being loaded.

LoadFile() is used to load a .lua script file from disk and store the compiled byte code as the top stack element.? It does not execute the chunk.? That must be performed via a call to Call() or PCall().? Code loaded in this matter can be dumped to disk via the LuaState::Dump() command.

Loading and Executing Lua Script Code from Memory

DoString() and DoBuffer() are used to load and execute scripts from memory.? They mirror lua_dostring() and lua_dobuffer() in functionality.

There are alternate version of DoString() and DoBuffer() taking a second parameter,a LuaObject describing the function environment for the block being loaded.

LoadString() and LoadBuffer() are used to load Lua scripts from memory and store the compiled byte code as the top stack element.? It does not execute the chunk.? That must be performed via a call to Call() or PCall().? Code loaded in this matter can be dumped to disk via the LuaState::Dump() command.

Finally,there are lua_WChar wide character equivalents of the above functions: DoWString(),LoadWString(),DoWBuffer(),and LoadWBuffer().

Retrieving a Global Variable

Global variables in a LuaState instance may be retrieved by one of a couple methods.

LuaObject obj = state->GetGlobal("MyGlobalVariable");

Alternatively,the basic LuaObject::operator[] referencing or the LuaObject::GetByName() functions may be used in conjunction with LuaState::GetGlobals().? (Both functions are described in greater detail below,in the LuaObject section.)

LuaObject globalsObj = state->GetGlobals();
LuaObject obj = globalsObj["MyGlobalVariable"];

You can also use a shortened form:

LuaObject obj = state->GetGlobals()["MyGlobalVariable"];

Note that some functions are for retrieval of LuaStackObjects.? These function names are usually followed with _Stack.

LuaStackObject obj1 = state->GetGlobals_Stack();
LuaStackObject obj2 = state->GetGlobal_Stack("MyGlobalVariable");

Retrieving the Registry

LuaObject obj = state->GetRegistry();
LuaStackObject obj2 = state->GetRegistry_Stack();

Retrieve a Stack Object

Any stack object can be retrieved via the Stack() function.

LuaStackObject obj = state->Stack(1);

The StackTop() function will return a LuaStackObject representing the current top of the stack.

LuaStackObject obj = state->StackTop();

Stack Functions

  • GetTop() - Mirrors lua_gettop().
  • SetTop(int index) - Mirrors lua_settop().
  • PushValue(int index) - Mirrors lua_pushvalue().
  • PushValue(LuaStackObject& object) - Mirrors lua_pushvalue().
  • Remove(int index) - Mirrors lua_remove().
  • Insert(int index) - Mirrors lua_insert().
  • Replace(int index) - Mirrors lua_remove().
  • CheckStack(int size) - Mirrors lua_checkstack().
  • XMove(LuaState* to,int n) - Mirrors lua_xmove().
  • Equal(int index1,int index2) - Mirrors lua_equal().
  • RawEqual(int index1,int index2) - Mirrors lua_rawequal().
  • LessThan(int index1,int index2) - Mirrors lua_lessthan().

Pushing values to the stack is accomplished via the following functions.

  • PushNil() - Mirrors lua_pushnil().
  • PushInteger(int n) - Mirrors lua_pushinteger().
  • PushNumber(lua_Number n) - Mirrors lua_pushnumber().
  • PushLString(const char* s,size_t len) - Mirrors lua_pushlstring().
  • PushLWString(const lua_WChar* s,size_t len) - Mirrors lua_pushlwstring().
  • PushString(const char* s) - Mirrors lua_pushstring().
  • PushWString(const lua_WChar* s) - Mirrors lua_pushwstring().
  • PushBoolean(bool value) - Mirrors lua_pushboolean().
  • PushLightUserData(void* p) - Mirrors lua_pushlightuserdata().

Pushing a closure to the stack has several overloads:

  • PushCClosure(lua_CFunction fn,int n) - Mirrors lua_pushcclosure().
  • PushCClosure(function,n) - Pushes a C callback function taking a LuaState* argument.? It can be either a global function,static function,or member function.
  • PushCFunction(lua_CFunction fn) - Pushes a C function to the stack.? No upvalues.

Retrieving Arguments

  • TypeError(narg,tname) - Mirrors luaL_typerror().
  • ArgError(narg,extramsg) - Mirrors luaL_argerror().
  • CheckLString(numArg,len) - Mirrors luaL_checklstring().
  • OptLString(numArg,def,len) - Mirrors luaL_optlstring().
  • CheckNumber(numArg) - Mirrors luaL_checknumber().
  • OptNumber(nArg,def) - Mirrors luaL_optnumber().
  • ArgCheck(condition,numarg,extramsg) - Mirrors luaL_argcheck().
  • CheckString(numArg) - Mirrors luaL_checkstring().
  • OptString(numArg,def) - Mirrors luaL_optstring().
  • CheckInt(numArg) - Mirrors luaL_checkint().
  • CheckLong(numArg) -? Mirrors luaL_checklong().
  • OptInt(numArg,def) - Mirrors luaL_optint().
  • OptLong(numArg,def) - Mirrors luaL_optlong().
  • CheckStack(int sz,const char* msg) - Mirrors luaL_checkstack().
  • CheckType(narg,t) - Mirrors luaL_checktype().
  • CheckAny(int narg) - Mirrors luaL_checkany().
  • CheckUData(int ud,const char* tname) - Mirrors luaL_checkudata().

Set Stack Table Values

The following mirror the standard C Lua APIs for stack table manipulation.? It is highly recommended LuaObject is used instead,as it provides a much better C++ alternative than the Lua stack.

  • SetTable(int index) - Mirrors lua_settable().
  • RawSet(int index) - Mirrors lua_rawset().
  • RawSetI(int index,int n) - Mirrors lua_rawseti().
  • SetMetaTable(int index) - Mirrors lua_setmetatable().
  • SetGlobals(int index) - Mirrors lua_setfenv().? Backward compatible.
  • SetFEnv(int index) - Mirrors lua_setfenv().
  • SetGlobal(const char *name) - Mirrors lua_setglobal().
  • Ref(int lock) - Mirrors luaL_ref().
  • Unref(int ref) - Mirrors luaL_unref().
  • SetDefaultMetaTable(int type) - Sets the default meta table for the given type with the table at the stack top.

Serializing to a Lua Text Data File

LuaPlus provides a comprehensive serialization facility for Lua data.? It is described in detail in the Serialization section below.

Class: LuaStateAuto/Owner (Unmanaged Only)

LuaStateAuto is an auto pointer encapsulation for a LuaState pointer.? When the LuaStateAuto goes out of scope,LuaState::Destroy() is automatically called on the contained state.? In a Release build,LuaStateAuto's accessors are inlined,and code generation is as if the LuaStateAuto object did not even exist.

Using LuaStateAuto is illustrated below:

{
    LuaStateAuto stateOwner;  // The state is automatically set to NULL.
    stateOwner = LuaState::Create();
    stateOwner->PushNil();
    // LuaState::Destroy() is automatically called here.
}

LuaStateOwner is derived from LuaStateAuto.? LuaStateOwner can automatically create the LuaState through the function call LuaState::Create.

{
    LuaStateOwner stateOwner;  // Automatically calls LuaState::Create().
    stateOwner->PushNil();
    // LuaState::Destroy() is automatically called here.
}

Since a LuaStateAuto object merely encapsulates the LuaState pointer,it is possible to retrieve that pointer by just assigning it.

LuaState* state = stateOwner;

Class: LuaObject

LuaPlus provides an API extension over the core of Lua wrapped in the class LuaObject.? A LuaObject gives the full functionality of core Lua's stack entities,but it does so without involving the stack at all.? In general,LuaObjects tend to run a little faster than the core Lua stack equivalent.

A LuaObject should be used for all communication with LuaPlus that is external to a callback function.? LuaStackObjects,are used in conjunction with callback functions,but the same functional interface is provided for consistency.

LuaObjects store a pointer to the parent LuaState.? In part,this is what makes the LuaWatchAddin work.? Most importantly,LuaObjects can just be passed around without any regard for the LuaState they came from.

It is also important to note LuaObjects are scope-driven.? So long as the LuaObject is in scope,the object is valid.? When it goes out of scope,the contents of the LuaObject will be garbage collected.? There is no need to run commands like lua_ref() to keep an object around.? Merely holding onto the LuaObject instance,be it as a member variable,global variable,or even local variable within a block of code is enough to ensure the LuaObject's existence.

A Reset() function is also provided.? It resets the LuaObject back to a default state where no Lua state is pointed to internally.

The sample code TestSuite performs an in-depth test of LuaObject and is a useful supplement to this documentation.? The sample TestScript is also used as a test bed for LuaObject concepts.

Object Type

A LuaObject contains an object of one of several different types.? These types are described in the Lua manual with the exception of the wide string type,a LuaPlus added type.

There are several ways to retrieve the type of the LuaObject.? To test for a specific type,one of the following functions may be called:

  • IsNil() - Tests if the object is nil.? Mirrors lua_isnil().
  • IsTable() - Tests if the object is a table.? Mirrors lua_istable().
  • IsUserData() - Tests if the object is userdata (including light userdata).? Mirrors lua_isuserdata().
  • IsCFunction() - Tests if the object is a C function.? Mirrors lua_iscfunction().
  • IsInteger() - Tests if the exact type of the object is a number.? See IsConvertibleToNumber() for the LuaObject equivalent of lua_isnumber().
  • IsNumber() - Tests if the exact type of the object is a number.? See IsConvertibleToNumber() for the LuaObject equivalent of lua_isnumber().
  • IsString() - Tests if the exact type of the object is a string.? See IsConvertibleToString() for the LuaObject equivalent of lua_isstring().
  • IsWString() - Tests if the exact type of the object is a wide string.? See IsConvertibleToWString() for the wide string equivalent of lua_isstring().
  • IsConvertibleToInteger() - Tests if the object is convertible to a number.? The object being tested can be a number,string,or wide string.? Mirrors lua_isnumber().
  • IsConvertibleToNumber() - Tests if the object is convertible to a number.? The object being tested can be a number,or wide string.? Mirrors lua_isnumber().
  • IsConvertibleToString() - Tests if the object is convertible to a string.? The object being tested can be a number or a string.? Mirrors lua_isstring().
  • IsConvertibleToWString() - Tests if the object is convertible to a wide string.? The object being tested can be a number or a wide string.? Mirrors lua_iswstring(),the wide character equivalent of lua_isstring().
  • IsFunction() - Tests if the object is a function.? Mirrors lua_isfunction().
  • IsNone() - Tests if the object is out of range on the stack.? Mirrors lua_isnone().
  • IsLightUserData() - Tests if the object is specifically light user data.
  • IsBoolean() - Tests if the object is a boolean.? Mirrors lua_isboolean().

Generically,the type may be retrieved via the Type() function.? It returns a value from the LuaState class's enumeration of Types:

enum Types
{
    TNONE = (-1),TNIL = 0,TBOOLEAN = 1,TLIGHTUSERDATA = 2,TNUMBER = 3,TSTRING = 4,TTABLE = 5,TFUNCTION = 6,TUSERDATA = 7,TTHREAD = 8,TWSTRING = 9,};

The actual string name of the type can be retrieved through LuaObject's TypeName() function.

Value Retrieval

After testing the LuaObject for the desired type,the stored value may be retrieved using one of LuaObject's Get*() functions.? All Get*() functions assert on the wrong type in Debug builds.

  • int ToInteger() - Mirrors lua_tonumber().? Attempts to retrieve a numeric value from the object,even if the object is a string.
  • lua_Number ToNumber() - Mirrors lua_tonumber().? Attempts to retrieve a numeric value from the object,even if the object is a string.
  • const char* ToString() - Mirrors lua_tostring().? Attempts to retrieve a string from the object.? If the object is a number,the object is converted to a string.
  • const lua_WChar* ToWString() - Mirrors lua_towstring().? Attempts to retrieve a wide string from the object.? It the object is a number,the object is converted to a wide character string.
  • int GetInteger() - Retrieves the integer the object represents.? Asserts if the object is not of a numeric type.
  • float GetFloat() - Retrieves the float the object represents.? Asserts if the object is not of a numeric type.
  • double GetDouble() - Retrieves the double the object represents.? Asserts if the object is not of a numeric type.
  • lua_Number GetNumber() - Retrieves the lua_Number the object represents.? Asserts if the object is not of a numeric type.
  • const char* GetString() - Retrieves the string the object represents.? Asserts if the object is not a single byte string type.
  • const lua_WChar* GetWString() - Retrieves the wide string the object represents.? Asserts if the object is not a double byte string type.
  • lua_CFunction GetCFunction() - Retrieves the C function pointer the object represents.? Asserts if the object is not a C function.
  • void* GetUserData() - Retrieves the userdata or light userdata the object represents.? Asserts if the object is not a userdata.
  • void* GetLightUserData() - Retrieves the light userdata the object represents.? Asserts if the object is not a light userdata.
  • bool GetBoolean() - Retrieves the boolean the object represents.? Asserts if the object is not a boolean convertible type.

If the LuaObject is an ANSI or wide character string,the length of the string in characters may be retrieved via StrLen().? The function ToStrLen() may be used to automatically convert numbers up to strings and retrieve the length.? ToStrLen()'s behavior is a mirror of lua_strlen().

For objects of type table,function,userdata,or light userdata,the internal Lua storage pointer can be retrieved via the function GetLuaPointer().

LuaObject obj = state->GetGlobal("SomeVariable");
if (obj.IsString())
{
    const char* str = obj.GetString();
}

Value Storage

For a stack Lua value,the programmer uses Push*() functions to get user values on the stack.? Since LuaObjects aren't stack based,an alternate scheme was devised.

To assign a value to any LuaObject,use one of the Assign*() functions.

  • AssignNil(LuaState* state)
  • AssignBoolean(LuaState* state,bool value)
  • AssignInteger(LuaState* state,int value)
  • AssignNumber(LuaState* state,double value)
  • AssignString(LuaState* state,const char* value)
  • AssignWString(LuaState* state,const lua_WChar* value)
  • AssignUserData(LuaState* state,void* value)
  • AssignLightUserData(LuaState* state,void* value)
  • AssignObject(LuaState* state,LuaObject& value)
  • AssignNewTable(LuaState* state,int narray = 0,int nhash = 0)

For example,to assign the string "Hello,world!" to a LuaObject:

LuaObject strObj;
strObj.AssignString(state,"Hello,world!");

Table Creation

There are two approaches for table creation built into LuaObject.? The first is provided through the CreateTable() suite of functions.? CreateTable() works similarly to the Set*() functions described below in that it is assumed the current LuaObject is a table.? The first argument to CreateTable() is a table key.? The key is used to make a new entry in the current LuaObject table and assign its value as an empty table.

The second approach to table creation is via the AssignNewTable() function.? When called,an empty Lua table is created in the current LuaObject.

LuaObject globalsObj = state->GetGlobals();
LuaObject myArrayOfStuffTableObj = globalsObj.CreateTable("MyArrayOfStuff");

LuaObject aStandaloneTableObj;
aStandaloneTableObj.AssignNewTable(state);

Table Count

When the LuaObject is a table,the functions for manipulating tables become available.? A few functions exist for retrieving various types of table counts.

For the following table:

MyTable =
{
    WindSpeed = 50,Value = 'Hello',10,20,30
}

Calling GetN() returns 3.? GetN() uses Lua's table.getn() function internally to retrieve the count.? table.getn() only considers contiguous numeric keys starting at 1 to be the count.

GetCount() also only considers contiguous numeric keys starting at 1.? It would also return 3 for the table above.? However,for one shot table counts,GetCount() generally runs much faster.

Finally,GetTableCount() exists to return the actual number of (non-contiguous) keys in the table.? For MyTable above,the table count would be 5.

Table Data Lookups

When the LuaObject is a table,the functions for manipulating tables become available.? If the LuaObject is not a table and those functions are used,they will assert.

operator[] has been overloaded to accept a key type of const char*,int,or LuaObject.? Using operator[] allows lookups to be very naturally represented,much like using Lua script code.

state->DoString("MyTable = { WindSpeed = 50,30 }");

LuaObject myTableObj = state->GetGlobals()["MyTable"];
LuaObject windSpeedObj = myTableObj["WindSpeed"];

LuaObject is20Obj = myTableObj[2];

LuaObject keyObj;
keyObj.AssignString(state,"Value");

LuaObject valueObj = myTableObj[keyObj];

Although not usually needed,spelled out forms of the table retrieval functions are:

  • GetByName(const char* key)
  • GetByIndex(int index)
  • GetByObject(const LuaObject& obj)
  • GetByObject(const LuaStackObject& obj)

Table Data Storage

The LuaObject table setting functions all start with Set*().

There are 3 overloaded Set*() functions per value type.? Each takes one of three key types for the key-value pair arguments.

  • A string specified via const char*.
  • An integer (int).
  • A LuaObject.

The Set*() functions are listed below.? key is one of the 3 types listed above.

  • SetNil(key)
  • SetBoolean(key,bool value)
  • SetInteger(key,int value)
  • SetNumber(key,double value)
  • SetString(key,const char* value)
  • SetWString(key,const lua_WChar* value)
  • SetUserData(key,void* value)
  • SetLightUserData(key,void* value)
  • SetObject(key,LuaObject& value)

Each Set*() function returns a reference to the current object,allowing chaining of multiple Set*() functions in a single statement.

Example:

LuaObject tableObj;
tableObj.AssignNewTable(state);
tableObj.SetString("MyKey",world!");

LuaObject globalsObj = state->GetGlobals();
globalsObj.SetBoolean("InUse",true).SetNumber(5,2000);

Table Data Lookups

The Lookup() function provides a simple method of recursively looking up a table entry by string.? It accepts period separated string key entries.

LuaObject globalsObj = state->GetGlobals();
LuaObject valueObj = globalsObj.Lookup("Child1.Child2.Value1");

Table Manipulation

Some of the calls provided through the table library of functions are more simply encapsulated in LuaObject.? The current set of functions are Insert() (mirroring table.insert),Remove() (mirroring table.remove),and Sort() (mirroring table.sort).

Cloning Objects

Another LuaObject method,Clone(),allows simple cloning of a LuaObject.? The clone operation is a deep clone for Lua tables,but for any other values,a simple clone is performed.? This should be fine for most needs,especially where values like userdata can just be a simple pointer copy.

The Clone() method does not handle cyclic tables.? You will either run out of memory or stack overflow if you attempt a clone operation on a cyclic table.

Comparing Objects

Two LuaObjects may be compared by using the == or < operators.? The internal comparisons are done through lua_equal() and lua_lessthan(),which is equivalent to their Lua counterparts.

Implicit Conversion Between LuaStackObject and LuaObject

On many occasions,it is still necessary to access an object on the Lua stack.? Callback functions receive an array of LuaStackObjects as arguments.? Generally,the APIs for a LuaStackObject and a LuaObject are similar enough to not be an issue when writing code.? LuaObjects are,however,the preferred way of accessing objects maintained by Lua,since the stack doesn't need to be taken into consideration.

Turning a LuaStackObject into a LuaObject is as simple as making an assignment:

LuaStackObject stack1Obj(state,1);
LuaStackObject stack2Obj(state,2);

LuaObject nonStack1Obj(stack1Obj);
// or
LuaObject nonStack2Obj = stack2Obj;

Pushing a LuaObject onto the Lua Stack

The cases where you would need to push a LuaObject onto the Lua stack are rare.? Nonetheless,the facility is provided through LuaObject's PushStack() function.

LuaObject tableObj(state);
tableObj.AssignNewTable();
tableObj.SetString("Key","My String");

// It's often good practice to use a LuaAutoBlock here.
tableObj.PushStack();    // Be sure to clean it up when you're done!

Registering Callbacks

Unmanaged Proper LuaPlus callbacks are of the function signature:
int Callback(LuaState* state);

As a convenience mechanism,the Lua stack is available through a class called LuaStack.? It will usually be used as the first line of a callback function.

LuaPlus's callbacks use a simple functor mechanism that masks away the differences between global functions,non-virtual member functions,and virtual member functions.

Lua standard C-style callbacks can also be used,although they aren't as functionally robust as LuaPlus callbacks.

An example follows:

static int LS_LOG(LuaState* state)
{
    printf("In static function/n");
    return 0;
}


class Logger
{
public:
    int LS_LOGMEMBER(LuaState* state)
    {
        LuaStack args(state);
        printf("In member function.  Message: %s/n",args[1].GetString());
        return 0;
    }

    virtual int LS_LOGVIRTUAL(LuaState* state)
    {
        printf("In virtual member function/n");
        return 0;
    }
};


LuaObject globalsObj = state->GetGlobals();
globalsObj.Register("LOG",LS_LOG);
state->DoString("LOG()");

Logger logger;
globalsObj.Register("LOGMEMBER",logger,&Logger::LS_LOGMEMBER);
state->DoString("LOGMEMBER('The message')");

globalsObj.Register("LOGVIRTUAL",&Logger::LS_LOGVIRTUAL);
state->DoString("LOGVIRTUAL()");

Callback functions are registered with the Register() function.? LuaObject provides several overloaded Register() functions:

void Register( const char* funcName,lua_CFunction function,int nupvalues = 0 );
void Register( const char* funcName,int (*func)(LuaState*),const Callee& callee,int (Callee::*func)(LuaState*),int nupvalues = 0 );

LuaObject provides a wide range of function registration facilities,including standard Lua callbacks and non-functor LuaPlus-style callbacks.? Additionally,arrays of functions may be registered,too.

Managed Proper LuaPlus callbacks are of defined through the Managed C++ delegate:
public __delegate int LuaPlusCallback(LuaState* state);

An example follows:

public int LS_LOG(LuaState state)
{
    Console.WriteLine("In member function.  Message: {0}/n",state.Stack(1).GetString());
    return 0;
}

LuaObject globalsObj = state.GetGlobals();
globalsObj.Register("LOG",new LuaPlusCallback(Logger.LS_LOG));
state->DoString("LOG()");

Registering Object Dispatch Functors

Unmanaged Even though Register() can dispatch to C++ member functions,it uses a 'this' pointer as provided by the second argument passed to the function.? The 'this' pointer is constant,and Register() is not suited for mirroring class hierarchies in Lua.

The solution to the 'this' pointer issue is through RegisterObjectFunctor().? It is a specialized form of Register() where a 'this' pointer isn't provided during the closure registration.? Instead,it is retrieved from either the calling userdata or the calling table's __object member,which must be a full or light userdata.

As an example,we want to mirror a class called MultiObject:

class MultiObject
{
public:
    MultiObject(int num) :
        m_num(num)
    {
    }

    int Print(LuaState* state)
    {
        printf("%d/n",m_num);
        return 0;
    }

    void Print2(int num)
    {
        printf("%d %d/n",m_num,num);
    }

protected:
    int m_num;
};

The best way to implement C++ objects mirrored in Lua is through metatables.? We'll start by creating a metatable and adding the MultiObject::Print() function to it.

LuaObject metaTableObj = state->GetGlobals().CreateTable("MultiObjectMetaTable");
metaTableObj.SetObject("__index",metaTableObj);
metaTableObj.RegisterObjectFunctor("Print",&MultiObject::Print);

Now,we'll give two C++ objects implementations in Lua called obj1 and obj2.? We set each Lua table's metatable to be the metatable we created above:

MultiObject obj1(10);
LuaObject obj1Obj = state->BoxPointer(&obj1);
obj1Obj.SetMetaTable(metaTableObj);
state->GetGlobals().SetObject("obj1",obj1Obj);

MultiObject obj2(20);
LuaObject obj2Obj = state->BoxPointer(&obj2);
obj2Obj.SetMetaTable(metaTableObj);
state->GetGlobals().SetObject("obj2",obj2Obj);

Everything is set up to handle proper dispatching now.? To illustrate,a few DoString() calls will dispatch to the correct objects:

state->DoString("obj1:Print()");
state->DoString("obj2:Print()");

obj1 and obj2 were both created as userdata objects with metatables.? The other approach involves assigning a full or light userdata representing the C++ object to a table's __object member.

LuaObject table1Obj = state->GetGlobals().CreateTable("table1");
table1Obj.SetLightUserData("__object",&obj1);
table1Obj.SetMetaTable(metaTableObj);

LuaObject table2Obj = state->GetGlobals().CreateTable("table2");
table2Obj.SetLightUserData("__object",&obj2);
table2Obj.SetMetaTable(metaTableObj);

state->DoString("table1:Print()");
state->DoString("table2:Print()");

Above,two Lua tables called table1 and table2 are created and their __object members are assigned to the C++ obj1 and obj2 objects respectively.? After the assignments are done,two DoString() calls are run to illustrate the correct callback dispatching.

Registering Functions Directly

Unmanaged LuaPlus supports registration of C++ functions directly through the RegisterDirect() function.
float Add(float num1,float num2)
{
    return num1 + num2;
}

LuaStateOwner state;
state->GetGlobals().RegisterDirect("Add",Add);
state->DoString("print(Add(10,5))");

Any functions registered in this fashion automatically receive built-in type checking for the incoming arguments.? If an argument is not valid,luaL_argassert is called.? For instance,in the above example,if Add was called with a non-numeric string,there would be a failure.

state->DoString("print(Add(10,'Hello'))");

Just as global functions can be registered,member functions can be registered,also.

void LOG(const char* message)
{
    printf("In global function: %s/n",message);
}


class Logger
{
public:
    void LOGMEMBER(const char* message)
    {
        printf("In member function: /n",message);
    }

    virtual void LOGVIRTUAL(const char* message)
    {
        printf("In virtual member function: %s/n",message);
    }
};


LuaObject globalsObj = state->GetGlobals();
globalsObj.RegisterDirect("LOG",LOG);
Logger logger;
globalsObj.RegisterDirect("LOGMEMBER",&Logger::LOGMEMBER);
globalsObj.RegisterDirect("LOGVIRTUAL",&Logger::LOGVIRTUAL);

state->DoString("LOG('Hello')");
state->DoString("LOGMEMBER('Hello')");
state->DoString("LOGVIRTUAL('Hello')");

The implementation built into LuaPlus in this version supports up to 7 parameters in the registered function.

Note: This direct registration of C++ functions and the recommended style for calling Lua functions are based around techniques presented in LuaBind (http://luabind.sourceforge.net/).? LuaBind provides a much more powerful function dispatching mechanism,including inheritance for classes.? I am not interested in making LuaPlus dependent on another library,and LuaBind is dependent on Boost (http://www.boost.org/).? Also,LuaPlus has no issue with making extensions to the core Lua code base to achieve the end result more efficiently.? LuaBind is built directly on top of the unmodified Lua 5.0 core.

Managed The support for direct registration of .NET functions is incomplete and slow at this time.? Hopefully,future improvements will bring it up to the usability level of the C++ counterpart.

Object Dispatch to Directly Called C++ Member Functions

Unmanaged Even though RegisterDirect() can dispatch directly to C++ member functions,and RegisterDirect() is not suited for mirroring class hierarchies in Lua.

The solution to the 'this' pointer issue is through RegisterObjectDirect().? It is a specialized form of RegisterDirect() where a 'this' pointer isn't provided during the closure registration.? Instead,which must be a full or light userdata.? The techniques presented in this section mirror closely the RegisterObjectFunctor() description above.

Using the above MultiObject sample,we'll add support for a directly called C++ member function to the metatable.

metaTableObj.RegisterObjectDirect("Print2",(MultiObject*)0,&MultiObject::Print2);

RegisterObjectDirect() has a slightly strange syntax in the second argument.? The reason this is the case is for the template expansion of the Callee object type to be correct.? It is possible to retrieve the Callee type from the third argument,but the current version of the LuaPlus Callback Dispatcher does not do so.? A future version may.

All that needs be done at this point are some calls to DoString():

state->DoString("obj1:Print2(5)");
state->DoString("obj2:Print2(15)");
state->DoString("table1:Print2(5)");
state->DoString("table2:Print2(15)");

Unregistering Callbacks

Unregistering a callback is as simple as setting its table entry to nil.

globalsObj.SetNil("LOG");

Calling Functions

LuaObject attempts to simplify the function calling interface of the core Lua API.? It does so by completely masking away the stack management.? Often,Lua function calls with arguments can be performed in a single line of code.

Recommended Style

Unmanaged By taking advantage of some C++ template tricks,we can directly call a Lua function as if it was C++ function.
LuaStateOwner state;
state->DoString("function Add(x,y) return x + y end");

LuaFunction<float> Add = state->GetGlobal("Add");
printf("Add: %d/n",Add(2,7));

The template LuaFunction<RT> takes a single argument for the parameter RT,the Return Type.? The types for the rest of the arguments can be deduced automatically,but the return type cannot.? The default return type is void.

LuaStateOwner state;
state->DoString("function Print(str) print(str) end");

LuaFunction<> Print = state->GetGlobal("Print");
Print("Hello,world!");

The built-in types LuaPlus understands for functions are:

  • bool
  • char
  • unsigned char
  • short
  • unsigned short
  • int
  • unsigned int
  • long
  • unsigned long
  • float
  • double
  • const char*
  • const lua_WChar*
  • lua_CFunction
  • LuaStateCFunction
  • LuaStackObject
  • LuaObject
  • const void*
  • LuaArgNil()
  • LuaLightUserData(pointer)
  • LuaUserData(pointer)

A more detailed discussion of the function dispatching mechanism may be found in the Lua Callback Dispatcher section below.

The implementation built into LuaPlus in this version supports up to 7 arguments.

Managed An experimental form of .NET to Lua function calling has been implemented for the .NET implementation.
LuaStateOwner state;
state->DoString("function Print(x,y) print(x,y) end");

LuaObject printObj = state->GetGlobal("Print");
printObj.Call(2,"Hi");

The types this technique understands is limited for now:

  • int
  • string
  • LuaStackObject
  • LuaObject

An unlimited number of arguments may be passed to the Call() function.

Iostream-like Style

Unmanaged LuaPlus also employs a convention similar to the Standard C++ library's iostream functionality.? A simple example follows:
LuaStateOwner state;
state->DoString("function Add(x,y) return x + y end");

LuaObject funcObj = state->GetGlobal("Add");

{
    LuaAutoBlock autoBlock(state);
    LuaCall call = funcObj();
    LuaStackObject retObj = call << 2 << 7 << LuaRun();
    printf("Add: %d/n",retObj.GetInteger());
}

The function call starts by "calling" the LuaObject.? LuaObject provides an overloaded function operator().? Then,each argument to the function is added to the argument list,left to right.? Finally,when all arguments are added,LuaRun() executes the function call.

It can't be avoided that a Lua function call puts return values on the stack.? The LuaStackObject returned by the LuaPlus function call is the first return value.? There may be more.

operator<< understands most Lua types.? The nil type is special,though.? In order to tell LuaPlus a nil should be inserted in the function's argument list,LuaArgNil() must be passed in.

LuaObject funcObj = state->GetGlobal("PrintIt");
LuaCall call = funcObj;
LuaStackObject retObj = call << "String" << LuaArgNil() << LuaRun();

LuaRun() takes an optional argument detailing the number of return values allowed.? By default,multiple return values are allowed.

LuaObject funcObj = state->GetGlobal("ThreeReturnValues");
LuaCall call = funcObj;
LuaStackObject retObj = call << LuaRun(1);  // Only accept one return value.
Managed No implementation exists for this at this time.

Metatables

The metatable for a LuaObject is retrieved via GetMetaTable().? Every table and userdata has a unique metatable.? The metatable for a basic type is shared.? See the Metatable Enhancements section.

A metatable can be changed for a LuaObject via the SetMetaTable() function.? If the LuaObject represents a table or userdata,the metatable change is as per standard Lua.? If the LuaObject is a basic type,the metatable is changed for all basic types.

Class: LuaTableIterator

LuaPlus provides a class called LuaTableIterator to ease the table iteration process.? Its use is far simpler,safer,and more natural looking than the standard Lua table iteration function (lua_next()/lua_pop()).? The iterator is not STL compliant in its current form.

LuaStateOwner state;
state.DoString( "MyTable = { Hi = 5,Hello = 10,Yo = 6 }" );

LuaObject obj = state.GetGlobals()[ "MyTable" ];
for ( LuaTableIterator it( obj ); it; it.Next() )
{
    const char* key = it.GetKey().GetString();
    int num = it.GetValue().GetInteger();
}

If the LuaWatchAddin is installed,the key and value portions of the LuaTableIterator object will be displayed as it is traversed.

LuaTableIterator is fully documented in LuaPlus.h.

Class: LuaStackObject

LuaPlus does not use integers to represent stack objects.? Instead,those stack indices are wrapped in a LuaStackObject.? LuaStackObjects can be passed directly to a Lua C function,if needed,but it is advised to go through the LuaPlus version of the function.

Using a LuaObject is usually the better way to go,since a LuaObject relieves the user of any stack management at all.? LuaStackObjects are available for use in callback functions or in special case stack management scenarios.

LuaStackObjects also store a pointer to the parent LuaState.? In part,this is what makes the LuaWatchAddin work.? Most importantly,LuaStackObjects can just be passed around without any regard for the LuaState they came from.

Most LuaStackObject functions mirror LuaObject functions of the same name,so see the section above for more detail.

  • Push()/Pop().

Class: LuaRefObject (Unmanaged Only)

(Note: Using LuaObject,there is no need to use this class.)

LuaPlus enhances the Lua ref table facility by allowing ref'ed objects to be used without using GetRef() to push them onto the stack.? LuaRefObject encapsulates this new functionality.? Assigning a LuaObject (or another LuaRefObject) to a LuaRefObject instance will cause a lua_ref() to occur.? When the LuaRefObject goes out of scope,lua_unref() is called.? LuaRefObject is derived from LuaObject and can operate on ref'ed objects without issue.

The LuaWatchAddin displays the contents of LuaRefObjects.

Class: LuaStackTableIterator

A LuaStackTableIterator is almost identical to the LuaTableIterator above,except it provides support for iterating using the stack,similar to how core Lua does it.

LuaStackTableIterator is fully documented in LuaPlus.h.

Class: LuaAutoBlock

Nothing can be more frustrating than paying attention to stack management.? Which function allocates which entry on the stack?? How many entries?? Did it get popped?? Where is that stack leak at?? LuaAutoBlock serves as a fairly useful approach to solving these problems.

LuaAutoBlock is a C++ class whose constructor stores the index of the stack top.? At destruction time,it sets the stack top to the stored index.? By providing this functionality as an object,the stack is guaranteed to be restored,regardless of exit points from a function or loop block.

Note: When using the LuaObject class,there is no need to worry about stack management,and so LuaAutoBlock provides no benefits in that situation.

{
    LuaAutoBlock autoBlock(state);
    LuaStackObject testObj = state->GetGlobals_Stack()["Test"]; // Does this allocate a stack item?
    state->PushString["A string"]; // Does this?
    testObj.SetNumber("Value",5); // Does this?
    // Who cares? LuaAutoBlock automatically cleans it up.
}

Class: LuaStateOutFile (Unmanaged Only)

LuaStateOutFile and derived classes are used in conjunction with LuaState::DumpObject().? When a LuaStateOutFile object is passed to DumpObject(),that object is used for writing the Lua dump file.? The application can derive from LuaStateOutFile to change the default dumping behavior.

Namespace: LuaPlus::LuaHelper (Unmanaged Only)

The LuaHelper namespace contains some useful helper functions for retrieving values from LuaObjects.? The helper functions perform a lookup into a table for a certain key.? If the key is required to be found and is not present,an assertion is triggered.? Otherwise,the found value or a default value is returned.

The following helper functions are available:

  • GetBoolean()
  • GetFloat()
  • GetLightUserData()
  • GetString()
  • GetTable()

New Features

Serialization

The LuaPlus distribution can write a Lua table into a nicely formatted text file.? All data types are handled,although some write themselves out as comments (functions,threads).

A table can be written both from Lua and C++.? The C++ LuaState function prototypes are:

bool DumpObject(const char* filename,const char* name,LuaObject& value,unsigned int flags = DUMP_ALPHABETICAL,int indentLevel = 0,unsigned int maxIndentLevel = 0xffffffff);
bool DumpObject(const char* filename,LuaObject& key,unsigned int maxIndentLevel = 0xffffffff);

bool DumpObject(LuaStateOutFile& file,unsigned int maxIndentLevel = 0xffffffff);
bool DumpObject(LuaStateOutFile& file,unsigned int maxIndentLevel = 0xffffffff);

bool DumpGlobals(const char* filename,unsigned int maxIndentLevel = 0xFFFFFFFF);
bool DumpGlobals(LuaStateOutFile& file,unsigned int maxIndentLevel = 0xFFFFFFFF);
  • filename - The name of the file to write to disk or a "@" string for logging to OutputDebugString (in Windows).
  • file - A LuaStateOutFile instance.
  • name - The name of the initial Lua table to write to disk.
  • key - The key name of the initial Lua table to write to disk.? This is usually a string,but it could be a number,too.
  • value - The value to write.
  • flags - One of three flags may be intermixed with each other:
    • DUMP_ALPHABETICAL - Alphabetize the keys when writing to the file.
    • DUMP_WRITEALL - Write all Lua objects out,including function and user data information.
    • DUMP_WRITETABLEPOINTERS - If DUMP_WRITEALL is specified,the actual memory addresses of tables are written in comment form.
  • indentLevel - The number of tabs to indent each line.
  • maxIndentLevel - The maximum number of nested tables allowed in the write.? If this value is exceeded,then no carriage returns are inserted.

The Lua functionality is very similar in form.

function LuaDumpObject(file,key,value,alphabetical,indentLevel,maxIndentLevel,writeAll)
function LuaDumpGlobals(file,writeAll)
  • file - The name of the file to write to disk,a "@" string for logging to OutputDebugString (in Windows),or a FILE* user data (say,from io.open()),
  • key - The key name of the initial Lua table to write to disk.? This is usually a string,too.
  • value - The value to write.
  • alphabetical - If true,each table's keys are sorted.? (Optional: Defaults to true.)
  • indentLevel - The number of tabs to indent each line.? (Optional: Defaults to 0.)
  • maxIndentLevel - The maximum number of nested tables allowed in the write.? If this value is exceeded,then no carriage returns are inserted.? (Optional: Defaults to 0xFFFFFFFF.)
  • writeAll - If true,writes all Lua objects out,including function and user data information. (Optional: Defaults to false.)

So,in a C++ application,an example usage of the serialization APIs might be:

LuaStateOwner state(false);
state->DoString("GlobalTable = { 1,2,3,4 }");
state->DoString("GlobalValue = 5");
state->DumpGlobals("c://dump.lua");

or like:

LuaStateOwner state;
state->DoString("Table = { 0,1,'Hello',nil,'Hi',Yo = 'My Stuff',NobodysHome = 5,NestedTable = { 1,{ 'String',},{ 'Table2' } },{ 'String1' } }");
state->DumpObject("c://dump.lua","Table",state->GetGlobals()["Table"]);

Wide Character Strings

Wide character support is built-in as a native LuaPlus type.? While it is entirely possible to represent a wide character string using a regular Lua 8-bit clean string,there is no way of determining whether the given string is wide or not.? The secondary problem involves the use of standard string functionality,such as the concatenation operator.? If a wide character string is represented as a normal 8-bit Lua string,special functions would have to be written to perform operations on the string (i.e. concatenation of two Lua 8-bit clean strings which represent wide characters).? Rather than require the user to keep track,a wide character string type is available.

Wide character strings can be entered into Lua script similar to the approach used by C code.

L"Wide characters"

By inserting an L in front of the quote,the LuaPlus lexer creates a wide character representation of the above string.? If the string was entered as a regular Lua string,the Unicode equivalent would be simulated as follows,and the string below assumes a certain architecture's endianness.

"W/000i/000d/000e/000 /000c/000h/000a/000r/000a/000c/000t/000e/000r/000s/000/000/000"

In the event it is necessary to insert wide character codes in the wide character string,an additional property of the L"" approach may be used.? 16-bit characters may be entered using hexadecimal notation,in the same way as C:

L"Wide characters: /x3042/x3043"

A new Lua library,located in lwstrlib.c,has been added for the new functionality.? In most respects,it mirrors the ANSI string library,lstrlib.c.

  • LUA_TWSTRING type added.? Mirrors LUA_TSTRING.
  • print() has been upgraded to take Unicode strings as input.
  • tonumber() can take a Unicode string as a parameter.
  • If tostring() receives a Unicode string as input,it converts it to ANSI and returns it.
  • towstring() added.? If towstring() receives an ANSI string as input,it converts it to Unicode and returns it.
  • fh:read() can read Unicode files/strings if the input string is Unicode.? The file must be opened in binary mode.
  • fh:write() can write Unicode strings.

New String Formatting Enhancements

Much like wide character string,ANSI strings can use the hexadecimal character notation to insert bytes into the string:

str = "Hel/x80o"

Memory Allocators

This distribution replaces the #define approach to memory allocation within Lua with a callback mechanism,where the memory allocators can be replaced on a per Lua state basis.? This allows a powerful mechanism to be employed to adjust memory allocation strategies on a per state basis.

For purposes of better memory tracking,the realloc() callback allows a void pointer of user data,an allocation name,and allocation flags to be passed along.? All of these arguments are optional,but they are available if the memory allocation callback needs them.

The only allocation flag available is LUA_ALLOC_TEMP.? A memory manager could react to the LUA_ALLOC_TEMP flag,for instance,by allocating the code for the main function of a Lua file at the top of the heap.? If all other Lua allocations happen at the bottom of the heap,no holes will be left in memory when the LUA_ALLOC_TEMP flagged allocation is garbage collection.

The callbacks look like:

static void* luaHelper_ReallocFunction(void* ptr,int oldsize,int size,void* data,const char* allocName,unsigned int allocFlags)
{
    return realloc(ptr,size);
}

static void luaHelper_FreeFunction(void* ptr,void* data)
{
    free(ptr);
}

The allocation functions must be assigned before a Lua global state is created,in a fashion similar to below.? It is good practice to restore the previous callbacks.

lua_ReallocFunction oldReallocFunc;
lua_FreeFunction oldFreeFunc;
void* oldData;
lua_getdefaultmemoryfunctions(&oldReallocFunc,&oldFreeFunc,&oldData);
lua_setdefaultmemoryfunctions(MyReallocFunction,MyFreeFunction,myUserData);
LuaStateOwner state;
lua_setdefaultmemoryfunctions(oldReallocFunc,oldFreeFunc,oldData);

User data enhancements

lua_boxpointer() and lua_unboxpointer() have the unfortunate disadvantage of decoupling their behavior from the lua_touserdata() call.? If you box a pointer,you have to unbox the pointer.? In the past,a boxed pointer was retrievable through lua_touserdata.

To that end,an implementation of the old lua_newuserdatabox() is included in the LuaPlus distribution as LuaPlus::NewUserDataBox().? Its value is retrieved via LuaObject::GetUserData() (or lua_touserdata()).

API Enhancements

  • lua_getmetatable() does not return the global default meta table in the case of non-tables or non-userdata.? Instead,it looks up the appropriate metatable for the given type and returns that.

Memory Optimizations

This section is out of date!

A whole host of functionality has been added to facilitate the optimization of memory usage in a tight memory environment.

  • luaM_setname() macro added and is used internally to name groups of allocations.? The name is passed into the realloc() callback function and may be used to better categorize allocations.

Metatable Enhancements

This section is out of date!

Basic type metatables are based heavily on Edgar Toernig's Sol implementation of unified methods.

In addition to standard Lua supporting metatables for?tables and userdata,a metatable per Lua's simple types (nil,?boolean,number,string,wstring,and function) has been added.? A string and wstring,have indistinguishable len() functions.

str = "Hello"
wstr = L"Hello"
print(str:len())
print(wstr:len())

The default method tables have been put into global names for convenience. They are named like the type but with a capital first letter (Nil,Number,String,WString,Function,Table,Userdata).

Method tables may be accessed from within Lua using the getmethodtable() function.

mytable = {} -- Save the old methods.
tableMethods = getmethodtable(mytable) newMethods = {  doNothing = function(self) end } -- Set the new methods.
setmethodtable(mytable, newMethods) mytable:doNothing()

In C,methods may be retrieved using the following functions:

LUA_API void lua_getmethods(lua_State *L,int index);
LUA_API void lua_getdefaultmethods(lua_State *L,int type);
LUA_API void lua_setmethods(lua_State *L,int index);

Lua Callback Dispatcher (Unmanaged Only)

A detailed discussion of the LuaPlus Call Dispatcher is found in this document.


Included Modules

clipboard

Has functions for retrieving and setting text from/to the clipboard.

clipboard.gettext()

Retrieves the text from the clipboard and returns it as a string.

clipboard.puttext(text)

Adds the text string text to the clipboard.

com

Heavily based on the LuaCom 1.0 (beta) implementation by Vinicius Almendra and Renato Cerqueira.? For the moment,the original LuaCom.pdf file is in the Docs/ directory.? There are a whole bunch of samples in the Test/ directory showing how some of the facilities of the COM module are used.

com.CreateObject(progID)

com.GetActiveObject(progID)

com.SafeArray()

FileFind

Some basic file finding facilities.? Usually,glob is sufficient for any file finds you might need.

FileFind.First(wildcard)

Returns a handle representing the first file matching wildcard.

FileFind.Next(self)

Retrieves the next file matching wildcard.

FileFind.Close(self)

Closes the file search.

FileFind.GetFileName(self)

Retrieves the file name of the currently matched file.

FileFind.GetLastWriteTime(self)

Retrieves the last write time as a time_t for the currently matched file.

FileFind.GetFileSize(self)

Retrieves the file size of the currently matched file.

FileFind.IsDirectory(self)

Determines if the currently matched entry is a directory.

iox

More advanced I/O operations than the basic io library.

io.readall(fileName)

Returns a buffer containing the contents of fileName. If there was an error reading the file,[nil,errorMessage] is returned.

io.writeall(fileName,buffer)

Writes buffer to fileName. If there was an error writing the file,errorMessage] is returned.

iox.access(fileName [,mode])

Returns 0 if the file has the given mode or -1 if it does not.? mode can be one of the following:

  • mode not specified - Does the file exist?
  • r - Is the file read-only?
  • w - Is the file write-only?
  • rw - Is the file readable and writable?

iox.CopyFile(existingFileName,newFileName)

Copies existingFileName to newFileName.? Returns true if the copy succeeded,false otherwise.

iox.CreateDirectory(path)

Creates the specified path.? All portions of the path up through the last backslash are created.

iox.DeleteFile(fileName)

Deletes the file specified by fileName.? Returns true if the deletion was successful,false otherwise.

iox.FileTimeToTime_t(arg1 [,arg2])

If arg1 and arg2 are specified and both are integers,then they are assumed to be the low and high date/times of a FILETIME structure.

If arg1 is a string,it is assumed to be in a format scannable by %I64u and will be put into the 64-bit component of the FILETIME structure.

Returns an integer describing the time_t representing the passed in FILETIME information.

iox.FindFirstFile(wildcard)

***

iox.FindNextFile()

***

iox.FindClose()

***

iox.FindGetFileName()

***

iox.FindIsDirectory()

***

iox.FindGetLastWriteTime()

***

iox.GetCurrentDirectory()

Retrieves the current working directory as a string.

iox.GetFileSize()

***

iox.GetWriteTime()

***

iox.MakeWritable()

***

iox.PathAddBackslash(path)

Adds a backslash to path,if necessary,and returns the new path string.

iox.PathAddExtension(path,extension)

Adds the extension to path,if path does not already have an extension.? Returns the new path as a string.

iox.PathAppend(path,extraPath)

Appends extraPath to path and returns the resulting path as a string.? A backslash is added between the two paths,if necessary.

iox.PathBuildRoot(driveNumber)

Returns a root path from the given driveNumber (where 0 is A:/ and 25 is Z:/).

iox.PathCanonicalize(path)

Returns a string describing the canonicalized version of path.

iox.PathCombine(path1,path2)

Returns a string describing the combined paths,path1 and path2.? Relative paths are resolved in this function.

iox.PathCommonPrefix(path1,path2)

Returns a string describing the common prefix of paths path1 and path2.

iox.PathCreate(path)

Creates the specified path.? All portions of the path up through the last backslash are created.

iox.PathDestroy(path)

Destroys the specified path removing all files in each destroyed directory.

iox.PathFileExists(path)

Returns true if the file exists,false otherwise.

iox.PathFindExtension(path)

Returns the numeric index of the '.' in the path's extension.? Returns nil if nothing found.

iox.PathFindFileName(path)

Returns the numeric index of the beginning of the file name in the path.? Returns nil if nothing found.

iox.PathFindNextComponent(path)

Returns the numeric index of the next component of the path (directory name or file name).? Returns nil if nothing found.

iox.PathFindOnPath(path)

Returns the numeric index of the next component of the path (directory name or file name).

iox.PathIsDirectory(path)

Returns true if the path is a valid directory,otherwise false.

iox.PathIsDirectoryEmpty(path)

Returns true if the path is a completely empty directory,otherwise false.

iox.PathIsFileSpec(path)

Returns true if the path has no path delimiting characters (a colon or backslash),otherwise false.

iox.PathIsHTMLFile(path)

Returns true if the path's extension is a known HTML file extension,otherwise false.

iox.PathIsLFNFileSpec(path)

Returns true if the path is not in 8.3 letter format,otherwise false.

iox.PathIsNetworkPath(path)

Returns true if the path is a network path,otherwise false.

iox.PathIsPrefix(path)

***

iox.PathIsRelative(path)

***

iox.PathIsRoot(path)

***

iox.PathIsSameRoot(path)

***

iox.PathIsSystemFolder(path)

***

iox.PathIsUNC(path)

***

iox.PathIsUNCServer(path)

***

iox.PathIsUNCServerShare(path)

***

iox.PathIsUNC(path)

***

iox.PathIsURL(path)

***

iox.PathMakeAbsolute(path)

***

iox.PathMakeBackSlash(path)

***

iox.PathMakeForwardSlash(path)

***

iox.PathMakePretty(path)

***

iox.PathMakeSystemFolder(path)

***

iox.PathMatchSpec(path)

***

iox.PathQuoteSpaces(path)

***

iox.PathRelativePathTo(path)

***

iox.PathRemoveArgs(path)

***

iox.PathRemoveBackslash(path)

***

iox.PathRemoveBlanks(path)

***

iox.PathRemoveExtension(path)

***

iox.PathRemoveFileSpec(path)

***

iox.PathRenameExtension(path)

***

iox.PathSearchAndQualify(path)

***

iox.PathSkipRoot(path)

***

iox.PathStripPath(path)

***

iox.PathStripToRoot(path)

***

iox.PathUndecorate(path)

***

iox.PathUnExpandEnvStrings(path)

***

iox.PathUnmakeSystemFolder(path)

***

iox.RemoveDirectory(path)

Destroys the specified path removing all files in each destroyed directory.

iox.SetCurrentDirectory(path)

Sets the current working directory.

iox.SetWriteTime()

***

iox.Sleep()

***

glob

Glob is a file globbing (matching) facility described in detail at http://www.codeproject.com/file/fileglob.asp.? The files found are returned in a table at completion.

table = glob.match("**")

pipe

Even though popen() is available under Windows,it is horribly broken,is only unidirectional,and only works for a command-line app.? The pipe module provides a facility whereby applications may use pipe facilities without these limitations.

pipe.popen(commandLine)

Returns a table with entries for stdin,stdout,and stderr.? These file handles work as if they were opened through the io library.

pipe.pclose(popenTable)

Immediately closes the stdin,and stderr pipes.? Normally,these would just be garbage collected,but if the application needed them to be shut down early,pipe.pclose() is the way to do it.

pipe.lines(commandLine)

Similar to the io.lines() facility.? Used in a for loop to simplify retrieving all the lines in a file (or in this case,pipe).

for line in pipe.lines("dir") do
    print(line)
end

windows

The windows module contains functions for manipulating the Microsoft Windows windowing system.? Documentation will be forthcoming.

Credits

This section has been missing forever,and although all copyright headers were left in the source code from the people who wrote them,it is nicer to list everybody here.

Credit goes out to:

  • The Kepler Project
  • Gustavo Niemeyer - Author of Lunatic Python.
  • Vinicius Almendra and Renato Cerqueira - Authors of LuaCOM
  • Reuben Thomas - Author of the bitwise operations library.
  • Fabio Mascarenhas - Author of the dotnetinterface library.
  • Luiz Henrique de Figueiredo - Author of the md5 and pack libraries.
  • Diego Nehab - The LuaThread library.
  • More to fill in.? Scouring the code base.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读