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;