diff --git a/LUA_API.rst b/LUA_API.rst index 54105d045..0b6ae863b 100644 --- a/LUA_API.rst +++ b/LUA_API.rst @@ -317,6 +317,24 @@ The ``df`` table itself contains the following functions and values: Equivalent to the method, but also allows a reference as proxy for its type. +* ``df.new(ptype[,count])`` + + Allocate a new instance, or an array of built-in types. + The ``ptype`` argument is a string from the following list: + ``string``, ``int8_t``, ``uint8_t``, ``int16_t``, ``uint16_t``, + ``int32_t``, ``uint32_t``, ``int64_t``, ``uint64_t``, ``bool``, + ``float``, ``double``. All of these except ``string`` can be + used with the count argument to allocate an array. + +* ``df.reinterpret_cast(type,ptr)`` + + Converts ptr to a ref of specified type. The type may be anything + acceptable to ``df.is_instance``. Ptr may be *nil*, a ref, + a lightuserdata, or a number. + + Returns *nil* if NULL, or a ref. + + Recursive table assignment ========================== diff --git a/Lua API.html b/Lua API.html index 02e7abf3c..2df8a7f22 100644 --- a/Lua API.html +++ b/Lua API.html @@ -615,6 +615,20 @@ lightuserdata (step is mandatory then).

  • df.is_instance(type,obj)

    Equivalent to the method, but also allows a reference as proxy for its type.

  • +
  • df.new(ptype[,count])

    +

    Allocate a new instance, or an array of built-in types. +The ptype argument is a string from the following list: +string, int8_t, uint8_t, int16_t, uint16_t, +int32_t, uint32_t, int64_t, uint64_t, bool, +float, double. All of these except string can be +used with the count argument to allocate an array.

    +
  • +
  • df.reinterpret_cast(type,ptr)

    +

    Converts ptr to a ref of specified type. The type may be anything +acceptable to df.is_instance. Ptr may be nil, a ref, +a lightuserdata, or a number.

    +

    Returns nil if NULL, or a ref.

    +
  • diff --git a/library/LuaWrapper.cpp b/library/LuaWrapper.cpp index 471dba640..7c15a27aa 100644 --- a/library/LuaWrapper.cpp +++ b/library/LuaWrapper.cpp @@ -447,10 +447,21 @@ Lua::ObjectClass Lua::IsDFObject(lua_State *state, int val_index) } static const char *const primitive_types[] = { - "string", NULL + "string", + "int8_t", "uint8_t", "int16_t", "uint16_t", + "int32_t", "uint32_t", "int64_t", "uint64_t", + "bool", "float", "double", + NULL }; static type_identity *const primitive_identities[] = { - df::identity_traits::get(), NULL + df::identity_traits::get(), + df::identity_traits::get(), df::identity_traits::get(), + df::identity_traits::get(), df::identity_traits::get(), + df::identity_traits::get(), df::identity_traits::get(), + df::identity_traits::get(), df::identity_traits::get(), + df::identity_traits::get(), + df::identity_traits::get(), df::identity_traits::get(), + NULL }; /** @@ -644,12 +655,32 @@ static int meta_new(lua_State *state) { int argc = lua_gettop(state); - if (argc != 1) - luaL_error(state, "Usage: object:new() or df.new(object)"); + if (argc != 1 && argc != 2) + luaL_error(state, "Usage: object:new() or df.new(object) or df.new(ptype,count)"); type_identity *id = get_object_identity(state, 1, "df.new()", true); - void *ptr = id->allocate(); + void *ptr; + + // Support arrays of primitive types + if (argc == 2) + { + int cnt = luaL_checkint(state, 2); + if (cnt <= 0) + luaL_error(state, "Invalid array size in df.new()"); + if (id->type() != IDTYPE_PRIMITIVE) + luaL_error(state, "Cannot allocate arrays of non-primitive types."); + + size_t sz = id->byte_size() * cnt; + ptr = malloc(sz); + if (ptr) + memset(ptr, 0, sz); + } + else + { + ptr = id->allocate(); + } + if (!ptr) luaL_error(state, "Cannot allocate %s", id->getFullName().c_str()); @@ -666,6 +697,48 @@ static int meta_new(lua_State *state) return 1; } +/** + * Method: type casting of pointers. + */ +static int meta_reinterpret_cast(lua_State *state) +{ + int argc = lua_gettop(state); + + if (argc != 2) + luaL_error(state, "Usage: df.reinterpret_cast(type,ptr)"); + + type_identity *id = get_object_identity(state, 1, "df.reinterpret_cast()", true); + + // Find the raw pointer value + void *ptr; + + if (lua_isnil(state, 2)) + ptr = NULL; + else if (lua_isnumber(state, 2)) + ptr = (void*)lua_tointeger(state, 2); + else + { + ptr = get_object_internal(state, NULL, 2, false, true); + if (!ptr) + luaL_error(state, "Invalid pointer argument in df.reinterpret_cast.\n"); + } + + // Convert it to the appropriate representation + if (ptr == NULL) + { + lua_pushnil(state); + } + else if (lua_isuserdata(state, 1)) + { + lua_getmetatable(state, 1); + push_object_ref(state, ptr); + } + else + push_object_internal(state, id, ptr); + + return 1; +} + static void invoke_resize(lua_State *state, int table, lua_Integer size) { lua_getfield(state, table, "resize"); @@ -1432,6 +1505,10 @@ static int DoAttach(lua_State *state) lua_pushcclosure(state, meta_new, 1); lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_NEW_NAME); + lua_rawgetp(state, LUA_REGISTRYINDEX, &DFHACK_TYPETABLE_TOKEN); + lua_pushcclosure(state, meta_reinterpret_cast, 1); + lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_CAST_NAME); + lua_rawgetp(state, LUA_REGISTRYINDEX, &DFHACK_TYPETABLE_TOKEN); lua_pushcclosure(state, meta_assign, 1); lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_ASSIGN_NAME); @@ -1463,6 +1540,8 @@ static int DoAttach(lua_State *state) lua_setfield(state, -2, "assign"); lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_IS_INSTANCE_NAME); lua_setfield(state, -2, "is_instance"); + lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_CAST_NAME); + lua_setfield(state, -2, "reinterpret_cast"); lua_pushlightuserdata(state, NULL); lua_setfield(state, -2, "NULL"); diff --git a/library/include/LuaWrapper.h b/library/include/LuaWrapper.h index 97b2e6980..9e4490220 100644 --- a/library/include/LuaWrapper.h +++ b/library/include/LuaWrapper.h @@ -77,6 +77,7 @@ namespace DFHack { namespace LuaWrapper { #define DFHACK_ASSIGN_NAME "DFHack::Assign" #define DFHACK_IS_INSTANCE_NAME "DFHack::IsInstance" #define DFHACK_DELETE_NAME "DFHack::Delete" +#define DFHACK_CAST_NAME "DFHack::Cast" extern LuaToken DFHACK_EMPTY_TABLE_TOKEN;