Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 27 additions & 38 deletions docs/dev/data-identity.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ contains both a pointer to the C++ object itself and a pointer to a ``type_ident
by that pointer. Note that the userdata object does not own the objects pointed to by these pointers, and the Lua engine is
never responsible for managing their lifetimes.

Most identities are instances of the single template class ``type_identity_for<T>``, which wraps the C++ type ``T``.
``type_identity_for<T>`` derives from a runtime base class selected at compile time by inspection of ``T``
(via ``std::is_enum``, ``std::is_pointer``, ``std::is_arithmetic``, container traits, and similar checks),
and implements the applicable virtual methods with ``if constexpr`` dispatch on the properties of ``T``.
A type can override the selection by defining a ``df_identity_base`` typedef naming the desired base;
the code generator emits this typedef for all generated compound types.

``type_identity`` defines the following public methods:

- ``byte_size``: returns the size, in bytes, of the object held
Expand All @@ -33,15 +40,17 @@ never responsible for managing their lifetimes.

- ``is_primitive``: indicates that ``lua_read`` will store a *copy* of the object on the Lua stack instead of a non-owning reference to it. Used for types that have direct representations in Lua: numbers, booleans, simple strings

- ``is_constructed``: indicates that creating a C++ instance of this type requires the use of a possibly nontrivial constructor. A type identity that is both primitive and constructed cannot be inserted into a container. At the moment the only type identity that is both primitive and constructed is ``stl_string_identity``, which wraps the C++ ``std::string`` type.
- ``is_constructed``: indicates that creating a C++ instance of this type requires the use of a possibly nontrivial constructor. A type identity that is both primitive and constructed cannot be inserted into a container. At the moment the only type identity that is both primitive and constructed is ``type_identity_for<std::string>``, which wraps the C++ ``std::string`` type.

- ``is_container``: indicates that the type is a container and thus implements the methods specific to ``container_identity``

- ``allocate``: allocate, and construct if necessary, a C++ instance of this type. This may fail if the type does not support construction.

- ``copy``: copy the object at ``src`` onto ``tgt``. This uses ``memmove`` for primitive types, and C++ copy-assignment (when possible) for other types

There are plethora of subclasses of ``type_identity``:
The identity class tree is divided into two layers: the *runtime base classes*, which are ordinary
(non-template) classes used for polymorphic dispatch, and the single leaf template ``type_identity_for<T>``,
which derives from the appropriate runtime base for the C++ type ``T`` that it wraps:

* ``type_identity`` the abstract base class of all type identities

Expand All @@ -55,69 +64,49 @@ There are plethora of subclasses of ``type_identity``:

* ``struct_identity`` C++ ``class`` or ``structure``

* ``global_identity`` holds, as a quasiobject, handles for all of the known Dwarf Fortress program-scope static objects as if they were fields of an object called ``global``

* ``union_identity`` C++ ``union``

* ``other_vectors_identity`` special-case identity for the categorized subvectors of objects that appears in many of Dwarf Fortress's "handler" classes

* ``virtual_identity`` polymorphic C++ ``class`` or ``structure`` having a virtual table to handle virtual dispatch

* ``stl_string_identity`` ``std::string``

* ``xlsx_file_handle_identity`` special case

* ``xlsx_sheet_handle_identity`` special case

* ``container_identity`` "containers" generally. note that all container types are homogeneous (that is, the elements of the container must all be of the same type). abstract base class

* ``bit_container_identity`` for containers that contain bools stored one element per *bit* (rather than per byte)

* ``bit_array_identity`` Dwarf Fortress's ``BitArray`` type

* ``stl_bit_vector_identity`` ``std::vector<bool>``
* ``bit_container_identity`` for containers that contain bools stored one element per *bit* (rather than per byte); also provides the ``get_item``/``set_item`` virtual interface

* ``buffer_container_identity`` C++ static arrays and raw C++ pointers acting as arrays of unspecified bound

* ``enum_list_attr_identity`` (template) metaobject with metadata about a C++ enumeration; may also include additional metadata

* ``ptr_container_identity`` containers that contain pointers

* ``stl_ptr_container_identity`` containers that are of the form ``std::vector<T*>`` for some ``T``

* ``ro_stl_container_identity`` (template) "read only containers"

* ``ro_stl_assoc_container_identity`` (template) ``std::map<KT,T>`` and ``std::unordered_map<KT,T>``

* ``stl_container_identity`` (template) ``std::vector<T>`` where ``T`` is *not* a pointer (and not ``bool``)

* ``opaque_identity`` opaque wrapper around any type, provides no functionality

* ``stl_string_identity`` ``std::string``

* ``function_identity_base`` abstract base class for ``function_identity``

* ``function_identity`` (template) wrapper around a C++ function that can be invoked from Lua

* ``primitive_identity`` wrapper around a primitive type. primitive types are fixed-length objects with no internal structure

* ``bool_identity`` ``bool``

* ``number_identity_base`` abstract base for numeric types

* ``float_identity_base`` abstract base for floating point types

* ``float_identity`` (template) ``double`` and ``float``

* ``integer_identity_base`` abstract base for integral types
* ``primitive_identity_base`` abstract base class for primitive types. primitive types are fixed-length objects with no internal structure

* ``integer_identity`` (template) ``int8_t``, ``int16_t``, ``int32_t``, ``size_t``, etc. lots of these
* ``number_identity_base`` abstract base for numeric types (and ``bool``); provides the ``isInteger`` discriminator

* ``pointer_identity`` any arbitrary C++ pointer (other than ``char*``)
* ``pointer_identity_base`` abstract base class for pointer identities; provides ``getTarget``

* ``ptr_string_identity`` C-style (``char *``) string
* ``type_identity_for<T>`` the leaf template that provides the identity of the C++ type ``T``. Its runtime
base class is selected by compile-time inspection of ``T`` (or by a ``df_identity_base`` typedef in ``T``),
covering all of the categories above: enums, bitfields, structs, unions, virtual classes, numbers,
pointers, C strings, ``std::string``, ``std::filesystem::path``, static arrays, containers, and opaque
types. Container categories are detected by capability rather than by type name: any type that provides
index-addressable elements (``t[i]`` yielding a ``T&``), bit-element access (a bool proxy or
``is_set``/``set`` accessors), mapped iteration (``mapped_type`` plus ``begin``/``end``), read-only
iteration, or a ``{ size, items[] }`` table (``enum_list_attr``) is treated as the corresponding kind of
container without being listed explicitly.

Types marked with "(template)" are C++ template types, all parameterized by a single typename.
``global_identity`` is an alias for ``type_identity_for<global_object>``, where ``global_object`` is an
empty placeholder type: it holds, as a quasiobject, handles for all of the known Dwarf Fortress
program-scope static objects as if they were fields of an object called ``global``.

Type identity object lifetime and mutability
============================================
Expand Down
2 changes: 1 addition & 1 deletion library/DataDefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ bool struct_identity::is_equivalent(const struct_identity* other) const
return true;
}

const std::string pointer_identity::getFullName() const
const std::string pointer_identity_base::getFullName() const
{
return (target ? target->getFullName() : std::string("void")) + "*";
}
Expand Down
59 changes: 28 additions & 31 deletions library/DataIdentity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,38 +21,35 @@
// without it the macro generates a syntax error when type is a template specification

namespace df {
#define NUMBER_IDENTITY_TRAITS(category, type, name) \
const category##_identity<type> identity_traits<type>::identity(name);
#define INTEGER_IDENTITY_TRAITS(type, name) NUMBER_IDENTITY_TRAITS(integer, type, name)
#define FLOAT_IDENTITY_TRAITS(type) NUMBER_IDENTITY_TRAITS(float, type, #type)
#define NUMBER_IDENTITY_TRAITS(type, name) \
const type_identity_for<type> identity_traits<type>::identity(name);
#define OPAQUE_IDENTITY_TRAITS_NAME(name, ...) \
const opaque_identity identity_traits<__VA_ARGS__ >::identity(sizeof(__VA_ARGS__), allocator_fn<__VA_ARGS__ >, name)
const type_identity_for<__VA_ARGS__ > identity_traits<__VA_ARGS__ >::identity(sizeof(__VA_ARGS__), allocator_fn<__VA_ARGS__ >, name)
#define OPAQUE_IDENTITY_TRAITS(...) OPAQUE_IDENTITY_TRAITS_NAME(#__VA_ARGS__, __VA_ARGS__ )

INTEGER_IDENTITY_TRAITS(char, "char");
INTEGER_IDENTITY_TRAITS(signed char, "int8_t");
INTEGER_IDENTITY_TRAITS(unsigned char, "uint8_t");
INTEGER_IDENTITY_TRAITS(short, "int16_t");
INTEGER_IDENTITY_TRAITS(unsigned short, "uint16_t");
INTEGER_IDENTITY_TRAITS(int, "int32_t");
INTEGER_IDENTITY_TRAITS(unsigned int, "uint32_t");
INTEGER_IDENTITY_TRAITS(long, "long");
INTEGER_IDENTITY_TRAITS(unsigned long, "unsigned long");
INTEGER_IDENTITY_TRAITS(long long, "int64_t");
INTEGER_IDENTITY_TRAITS(unsigned long long, "uint64_t");
INTEGER_IDENTITY_TRAITS(wchar_t, "wchar_t");
FLOAT_IDENTITY_TRAITS(float);
FLOAT_IDENTITY_TRAITS(double);

const bool_identity identity_traits<bool>::identity;
const stl_string_identity identity_traits<std::string>::identity;
const path_identity identity_traits<std::filesystem::path>::identity;
const ptr_string_identity identity_traits<char*>::identity;
const ptr_string_identity identity_traits<const char*>::identity;
const pointer_identity identity_traits<void*>::identity;
const stl_ptr_vector_identity identity_traits<std::vector<void*> >::identity;
const stl_bit_vector_identity identity_traits<std::vector<bool> >::identity;
const bit_array_identity identity_traits<BitArray<int> >::identity;
NUMBER_IDENTITY_TRAITS(char, "char");
NUMBER_IDENTITY_TRAITS(signed char, "int8_t");
NUMBER_IDENTITY_TRAITS(unsigned char, "uint8_t");
NUMBER_IDENTITY_TRAITS(short, "int16_t");
NUMBER_IDENTITY_TRAITS(unsigned short, "uint16_t");
NUMBER_IDENTITY_TRAITS(int, "int32_t");
NUMBER_IDENTITY_TRAITS(unsigned int, "uint32_t");
NUMBER_IDENTITY_TRAITS(long, "long");
NUMBER_IDENTITY_TRAITS(unsigned long, "unsigned long");
NUMBER_IDENTITY_TRAITS(long long, "int64_t");
NUMBER_IDENTITY_TRAITS(unsigned long long, "uint64_t");
NUMBER_IDENTITY_TRAITS(wchar_t, "wchar_t");
NUMBER_IDENTITY_TRAITS(float, "float");
NUMBER_IDENTITY_TRAITS(double, "double");
NUMBER_IDENTITY_TRAITS(bool, "bool");
const type_identity_for<std::string> identity_traits<std::string>::identity;
const type_identity_for<std::filesystem::path> identity_traits<std::filesystem::path>::identity;
const type_identity_for<char*> identity_traits<char*>::identity;
const type_identity_for<const char*> identity_traits<const char*>::identity;
const type_identity_for<void*> identity_traits<void*>::identity(nullptr);
const type_identity_for<std::vector<void*> > identity_traits<std::vector<void*> >::identity;
const type_identity_for<std::vector<bool> > identity_traits<std::vector<bool> >::identity;
const type_identity_for<BitArray<int> > identity_traits<BitArray<int> >::identity;

OPAQUE_IDENTITY_TRAITS(std::condition_variable);
OPAQUE_IDENTITY_TRAITS(std::fstream);
Expand All @@ -70,6 +67,6 @@ namespace df {

const buffer_container_identity buffer_container_identity::base_instance;

const stl_container_identity<std::vector<int32_t> > stl_vector_int32_t_identity("vector", identity_traits<int32_t>::get());
const stl_container_identity<std::vector<int16_t> > stl_vector_int16_t_identity("vector", identity_traits<int16_t>::get());
const type_identity_for<std::vector<int32_t> > stl_vector_int32_t_identity("vector", identity_traits<int32_t>::get());
const type_identity_for<std::vector<int16_t> > stl_vector_int16_t_identity("vector", identity_traits<int16_t>::get());
}
Loading
Loading