diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 63107456a..7d3c4d6bb 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -57,6 +57,7 @@ ColorText.cpp DataDefs.cpp DataStatics.cpp DataStaticsCtor.cpp +DataStaticsFields.cpp MiscUtils.cpp PluginManager.cpp TileTypes.cpp @@ -195,6 +196,14 @@ ADD_CUSTOM_COMMAND( ADD_CUSTOM_TARGET(generate_headers DEPENDS ${dfapi_SOURCE_DIR}/include/df/static.inc) +IF(UNIX) + # Don't produce debug info for generated stubs + SET_SOURCE_FILES_PROPERTIES(DataStatics.cpp DataStaticsCtor.cpp DataStaticsFields.cpp + PROPERTIES COMPILE_FLAGS "-g0") +ELSE(WIN32) +ENDIF() + + # Compilation ADD_DEFINITIONS(-DBUILD_DFHACK_LIB) diff --git a/library/DataDefs.cpp b/library/DataDefs.cpp index 30a4da271..c7b0d29dd 100644 --- a/library/DataDefs.cpp +++ b/library/DataDefs.cpp @@ -44,18 +44,107 @@ using namespace DFHack; * this list has to be plain data, so that it gets * initialized by the loader in the initial mmap. */ -virtual_identity *virtual_identity::list = NULL; +compound_identity *compound_identity::list = NULL; +std::vector compound_identity::top_scope; -virtual_identity::virtual_identity(const char *dfhack_name, const char *original_name, virtual_identity *parent) - : dfhack_name(dfhack_name), original_name(original_name), parent(parent), - prev(NULL), vtable_ptr(NULL), has_children(true) +compound_identity::compound_identity(size_t size, TAllocateFn alloc, + compound_identity *scope_parent, const char *dfhack_name) + : constructed_identity(size, alloc), scope_parent(scope_parent), dfhack_name(dfhack_name) { - // Link into the static list. Nothing else can be safely done at this point. - next = list; list = this; + next = list; list = this; +} + +void compound_identity::doInit(Core *) +{ + if (scope_parent) + scope_parent->scope_children.push_back(this); + else + top_scope.push_back(this); } -/* Vtable to identity lookup. */ static tthread::mutex *known_mutex = NULL; + +void compound_identity::Init(Core *core) +{ + if (!known_mutex) + known_mutex = new tthread::mutex(); + + // This cannot be done in the constructors, because + // they are called in an undefined order. + for (compound_identity *p = list; p; p = p->next) + p->doInit(core); + + //FIXME: ... nuked. the group was empty... +/* + // Read pre-filled vtable ptrs + OffsetGroup *ptr_table = core->vinfo->getGroup("vtable"); + for (virtual_identity *p = list; p; p = p->next) { + void * tmp; + if (ptr_table->getSafeAddress(p->getName(),tmp)) + p->vtable_ptr = tmp; + } + */ +} + +bitfield_identity::bitfield_identity(size_t size, TAllocateFn alloc, + compound_identity *scope_parent, const char *dfhack_name, + int num_bits, const bitfield_item_info *bits) + : compound_identity(size, alloc, scope_parent, dfhack_name), bits(bits), num_bits(num_bits) +{ +} + +enum_identity::enum_identity(size_t size, TAllocateFn alloc, + compound_identity *scope_parent, const char *dfhack_name, + int64_t first_item_value, int64_t last_item_value, + const char *const *keys) + : compound_identity(size, alloc, scope_parent, dfhack_name), + first_item_value(first_item_value), last_item_value(last_item_value), keys(keys) +{ +} + +struct_identity::struct_identity(size_t size, TAllocateFn alloc, + compound_identity *scope_parent, const char *dfhack_name, + struct_identity *parent, const struct_field_info *fields) + : compound_identity(size, alloc, scope_parent, dfhack_name), parent(parent), has_children(false) +{ +} + +void struct_identity::doInit(Core *core) +{ + compound_identity::doInit(core); + + if (parent) { + parent->children.push_back(this); + parent->has_children = true; + } +} + +bool struct_identity::is_subclass(struct_identity *actual) +{ + for (; actual; actual = actual->getParent()) + if (actual == this) return true; + + return false; +} + +virtual_identity::virtual_identity(size_t size, TAllocateFn alloc, + const char *dfhack_name, const char *original_name, + virtual_identity *parent, const struct_field_info *fields) + : struct_identity(size, alloc, NULL, dfhack_name, parent, fields), original_name(original_name), + vtable_ptr(NULL) +{ +} + +static std::map name_lookup; + +void virtual_identity::doInit(Core *core) +{ + struct_identity::doInit(core); + + name_lookup[getOriginalName()] = this; +} + +/* Vtable to identity lookup. */ std::map virtual_identity::known; virtual_identity *virtual_identity::get(virtual_ptr instance_ptr) @@ -78,8 +167,9 @@ virtual_identity *virtual_identity::get(virtual_ptr instance_ptr) virtual_identity *actual = NULL; - for (virtual_identity *p = list; p; p = p->next) { - if (strcmp(name.c_str(), p->getOriginalName()) != 0) continue; + auto name_it = name_lookup.find(name); + if (name_it != name_lookup.end()) { + virtual_identity *p = name_it->second; if (p->vtable_ptr && p->vtable_ptr != vtable) { std::cerr << "Conflicting vtable ptr for class '" << p->getName() @@ -103,14 +193,6 @@ virtual_identity *virtual_identity::get(virtual_ptr instance_ptr) return NULL; } -bool virtual_identity::is_subclass(virtual_identity *actual) -{ - for (; actual; actual = actual->parent) - if (actual == this) return true; - - return false; -} - void virtual_identity::adjust_vtable(virtual_ptr obj, virtual_identity *main) { if (vtable_ptr) { @@ -135,35 +217,6 @@ virtual_ptr virtual_identity::clone(virtual_ptr obj) return copy; } -void virtual_identity::Init(Core *core) -{ - if (!known_mutex) - known_mutex = new tthread::mutex(); - - // This cannot be done in the constructors, because - // they are called in an undefined order. - for (virtual_identity *p = list; p; p = p->next) { - p->has_children = false; - p->children.clear(); - } - for (virtual_identity *p = list; p; p = p->next) { - if (p->parent) { - p->parent->children.push_back(p); - p->parent->has_children = true; - } - } - //FIXME: ... nuked. the group was empty... -/* - // Read pre-filled vtable ptrs - OffsetGroup *ptr_table = core->vinfo->getGroup("vtable"); - for (virtual_identity *p = list; p; p = p->next) { - void * tmp; - if (ptr_table->getSafeAddress(p->getName(),tmp)) - p->vtable_ptr = tmp; - } - */ -} - bool DFHack::findBitfieldField(unsigned *idx, const std::string &name, unsigned size, const bitfield_item_info *items) { diff --git a/library/DataStatics.cpp b/library/DataStatics.cpp index 5ccabb7e1..4a77b3b1d 100644 --- a/library/DataStatics.cpp +++ b/library/DataStatics.cpp @@ -21,6 +21,8 @@ namespace { #define INIT_GLOBAL_FUNCTION_ITEM(type,name) \ if (global_table_->getAddress(#name,tmp_)) name = (type*)tmp_; +#define TID(type) (&identity_traits< type >::identity) + // Instantiate all the static objects #include "df/static.inc" #include "df/static.enums.inc" diff --git a/library/DataStaticsFields.cpp b/library/DataStaticsFields.cpp new file mode 100644 index 000000000..0e6e9957e --- /dev/null +++ b/library/DataStaticsFields.cpp @@ -0,0 +1,23 @@ +#include "Internal.h" +#include "DataDefs.h" +#include "MiscUtils.h" +#include "VersionInfo.h" + +#include "df/world.h" +#include "df/world_data.h" +#include "df/ui.h" + +#include "DataIdentity.h" + +#include + +#pragma GCC diagnostic ignored "-Winvalid-offsetof" + +#define TID(type) (&identity_traits< type >::identity) + +#define FLD(mode, name) struct_field_info::mode, #name, offsetof(CUR_STRUCT, name) +#define GFLD(mode, name) struct_field_info::mode, #name, 0 +#define FLD_END struct_field_info::END + +// Field definitions +#include "df/static.fields.inc" diff --git a/library/include/DataDefs.h b/library/include/DataDefs.h index 99694d949..2a9567182 100644 --- a/library/include/DataDefs.h +++ b/library/include/DataDefs.h @@ -45,47 +45,205 @@ namespace DFHack { class virtual_class {}; + enum identity_type { + IDTYPE_GLOBAL, + IDTYPE_PRIMITIVE, + IDTYPE_CONTAINER, + IDTYPE_BITFIELD, + IDTYPE_ENUM, + IDTYPE_STRUCT, + IDTYPE_CLASS + }; + + typedef void *(*TAllocateFn)(void*,const void*); + + class DFHACK_EXPORT type_identity { + size_t size; + + protected: + type_identity(size_t size) : size(size) {}; + + virtual void *do_instantiate() { + void *p = malloc(size); + memset(p, 0, size); + return p; + } + virtual void do_copy(void *tgt, const void *src) { + memmove(tgt, src, size); + }; + + public: + virtual ~type_identity() {} + + size_t byte_size() { return size; } + + virtual identity_type type() = 0; + }; + + class DFHACK_EXPORT constructed_identity : public type_identity { + TAllocateFn allocator; + + protected: + constructed_identity(size_t size, TAllocateFn alloc) + : type_identity(size), allocator(alloc) {}; + + virtual void *do_instantiate() { + return allocator ? allocator(NULL,NULL) : type_identity::do_instantiate(); + } + virtual void do_copy(void *tgt, const void *src) { + if (allocator) allocator(tgt,src); + else type_identity::do_copy(tgt, src); + }; + }; + + class DFHACK_EXPORT compound_identity : public constructed_identity { + static compound_identity *list; + compound_identity *next; + + const char *dfhack_name; + compound_identity *scope_parent; + std::vector scope_children; + static std::vector top_scope; + + protected: + compound_identity(size_t size, TAllocateFn alloc, + compound_identity *scope_parent, const char *dfhack_name); + + virtual void doInit(Core *core); + + public: + const char *getName() { return dfhack_name; } + + compound_identity *getScopeParent() { return scope_parent; } + const std::vector &getScopeChildren() { return scope_children; } + static const std::vector &getTopScope() { return top_scope; } + + static void Init(Core *core); + }; + + // Bitfields + struct bitfield_item_info { + const char *name; + int size; + }; + + class DFHACK_EXPORT bitfield_identity : public compound_identity { + const bitfield_item_info *bits; + int num_bits; + + public: + bitfield_identity(size_t size, TAllocateFn alloc, + compound_identity *scope_parent, const char *dfhack_name, + int num_bits, const bitfield_item_info *bits); + + virtual identity_type type() { return IDTYPE_BITFIELD; } + + int getNumBits() { return num_bits; } + const bitfield_item_info *getBits() { return bits; } + }; + + class DFHACK_EXPORT enum_identity : public compound_identity { + const char *const *keys; + int64_t first_item_value; + int64_t last_item_value; + + public: + enum_identity(size_t size, TAllocateFn alloc, + compound_identity *scope_parent, const char *dfhack_name, + int64_t first_item_value, int64_t last_item_value, + const char *const *keys); + + virtual identity_type type() { return IDTYPE_ENUM; } + + int getCount() { return int(last_item_value-first_item_value+1); } + const char *const *getKeys() { return keys; } + }; + + struct struct_field_info { + enum Mode { + END, + PRIMITIVE, + STATIC_STRING, + POINTER, + STATIC_ARRAY, + SUBSTRUCT, + CONTAINER, + STL_VECTOR_PTR + }; + Mode mode; + const char *name; + size_t offset; + type_identity *type; + size_t count; + enum_identity *eid; + }; + + class DFHACK_EXPORT struct_identity : public compound_identity { + struct_identity *parent; + std::vector children; + bool has_children; + + protected: + virtual void doInit(Core *core); + + public: + struct_identity(size_t size, TAllocateFn alloc, + compound_identity *scope_parent, const char *dfhack_name, + struct_identity *parent, const struct_field_info *fields); + + virtual identity_type type() { return IDTYPE_STRUCT; } + + struct_identity *getParent() { return parent; } + const std::vector &getChildren() { return children; } + bool hasChildren() { return has_children; } + + bool is_subclass(struct_identity *subtype); + }; + + class DFHACK_EXPORT global_identity : public struct_identity { + public: + global_identity(const struct_field_info *fields) + : struct_identity(0,NULL,NULL,"global",NULL,fields) {} + + virtual identity_type type() { return IDTYPE_GLOBAL; } + }; + #ifdef _MSC_VER typedef void *virtual_ptr; #else typedef virtual_class *virtual_ptr; #endif - class DFHACK_EXPORT virtual_identity { - static virtual_identity *list; + class DFHACK_EXPORT virtual_identity : public struct_identity { static std::map known; - - virtual_identity *prev, *next; - const char *dfhack_name; + const char *original_name; - virtual_identity *parent; - std::vector children; - + void *vtable_ptr; - bool has_children; protected: - virtual_identity(const char *dfhack_name, const char *original_name, virtual_identity *parent); + virtual void doInit(Core *core); static void *get_vtable(virtual_ptr instance_ptr) { return *(void**)instance_ptr; } public: - const char *getName() { return dfhack_name; } - const char *getOriginalName() { return original_name ? original_name : dfhack_name; } + virtual_identity(size_t size, TAllocateFn alloc, + const char *dfhack_name, const char *original_name, + virtual_identity *parent, const struct_field_info *fields); + + virtual identity_type type() { return IDTYPE_CLASS; } - virtual_identity *getParent() { return parent; } - const std::vector &getChildren() { return children; } + const char *getOriginalName() { return original_name ? original_name : getName(); } public: static virtual_identity *get(virtual_ptr instance_ptr); - - bool is_subclass(virtual_identity *subtype); + bool is_instance(virtual_ptr instance_ptr) { if (!instance_ptr) return false; if (vtable_ptr) { void *vtable = get_vtable(instance_ptr); if (vtable == vtable_ptr) return true; - if (!has_children) return false; + if (!hasChildren()) return false; } return is_subclass(get(instance_ptr)); } @@ -98,15 +256,10 @@ namespace DFHack public: bool can_instantiate() { return (vtable_ptr != NULL); } - virtual_ptr instantiate() { return can_instantiate() ? do_instantiate() : NULL; } + virtual_ptr instantiate() { return can_instantiate() ? (virtual_ptr)do_instantiate() : NULL; } static virtual_ptr clone(virtual_ptr obj); - protected: - virtual virtual_ptr do_instantiate() = 0; - virtual void do_copy(virtual_ptr tgt, virtual_ptr src) = 0; public: - static void Init(Core *core); - // Strictly for use in virtual class constructors void adjust_vtable(virtual_ptr obj, virtual_identity *main); }; @@ -135,12 +288,6 @@ namespace DFHack size_t size; const T *items; }; - - // Bitfields - struct bitfield_item_info { - const char *name; - int size; - }; } template @@ -164,33 +311,37 @@ inline int linear_index(const DFHack::enum_list_attr &lst, const st namespace df { + using DFHack::type_identity; + using DFHack::compound_identity; using DFHack::virtual_ptr; using DFHack::virtual_identity; using DFHack::virtual_class; + using DFHack::global_identity; + using DFHack::struct_identity; + using DFHack::struct_field_info; using DFHack::bitfield_item_info; + using DFHack::bitfield_identity; + using DFHack::enum_identity; using DFHack::enum_list_attr; using DFHack::BitArray; using DFHack::DfArray; template - struct enum_traits {}; + void *allocator_fn(void *out, const void *in) { + if (out) { *(T*)out = *(const T*)in; return out; } + else return new T(); + } template - struct bitfield_traits {}; + struct identity_traits { + static compound_identity *get() { return &T::_identity; } + }; template - class class_virtual_identity : public virtual_identity { - public: - class_virtual_identity(const char *dfhack_name, const char *original_name, virtual_identity *parent) - : virtual_identity(dfhack_name, original_name, parent) {}; - - T *instantiate() { return static_cast(virtual_identity::instantiate()); } - T *clone(T* obj) { return static_cast(virtual_identity::clone(obj)); } + struct enum_traits {}; - protected: - virtual virtual_ptr do_instantiate() { return new T(); } - virtual void do_copy(virtual_ptr tgt, virtual_ptr src) { *static_cast(tgt) = *static_cast(src); } - }; + template + struct bitfield_traits {}; template struct enum_field { diff --git a/library/include/DataIdentity.h b/library/include/DataIdentity.h new file mode 100644 index 000000000..679023fcf --- /dev/null +++ b/library/include/DataIdentity.h @@ -0,0 +1,175 @@ +/* +https://github.com/peterix/dfhack +Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#pragma once + +#include +#include +#include +#include + +#include "DataDefs.h" + +/* + * Definitions of DFHack namespace structs used by generated headers. + */ + +namespace DFHack +{ + class DFHACK_EXPORT primitive_identity : public type_identity { + public: + primitive_identity(size_t size) : type_identity(size) {}; + + virtual identity_type type() { return IDTYPE_PRIMITIVE; } + }; + + class DFHACK_EXPORT container_identity : public constructed_identity { + type_identity *item; + enum_identity *ienum; + + public: + container_identity(size_t size, TAllocateFn alloc, type_identity *item, enum_identity *ienum = NULL) + : constructed_identity(size, alloc), item(item), ienum(ienum) {}; + + virtual identity_type type() { return IDTYPE_CONTAINER; } + }; +} + +namespace df +{ + using DFHack::primitive_identity; + using DFHack::container_identity; + +#define ATOM_IDENTITY_TRAITS(type) \ + template<> struct identity_traits { \ + static primitive_identity identity; \ + static primitive_identity *get() { return &identity; } \ + }; \ + primitive_identity identity_traits::identity(sizeof(type)); + + ATOM_IDENTITY_TRAITS(char); + ATOM_IDENTITY_TRAITS(int8_t); + ATOM_IDENTITY_TRAITS(uint8_t); + ATOM_IDENTITY_TRAITS(int16_t); + ATOM_IDENTITY_TRAITS(uint16_t); + ATOM_IDENTITY_TRAITS(int32_t); + ATOM_IDENTITY_TRAITS(uint32_t); + ATOM_IDENTITY_TRAITS(int64_t); + ATOM_IDENTITY_TRAITS(uint64_t); + ATOM_IDENTITY_TRAITS(bool); + ATOM_IDENTITY_TRAITS(float); + ATOM_IDENTITY_TRAITS(std::string); + ATOM_IDENTITY_TRAITS(void*); + +#undef ATOM_IDENTITY_TRAITS + + // Container declarations + + template struct identity_traits > { + static primitive_identity *get(); + }; + + template struct identity_traits { + static container_identity *get(); + }; + + template struct identity_traits { + static container_identity *get(); + }; + + template struct identity_traits > { + static container_identity *get(); + }; + + template struct identity_traits > { + static container_identity *get(); + }; + + template struct identity_traits > { + static container_identity *get(); + }; + + template struct identity_traits > { + static container_identity *get(); + }; + + // Container definitions + + template + primitive_identity *identity_traits >::get() { + static primitive_identity identity(sizeof(FT)); + return &identity; + } + + template + container_identity *identity_traits::get() { + typedef T * container; + static container_identity identity(sizeof(container), &allocator_fn, + identity_traits::get()); + return &identity; + } + + template + container_identity *identity_traits::get() { + typedef T container[sz]; + static container_identity identity(sizeof(container), NULL, + identity_traits::get()); + return &identity; + } + + template + container_identity *identity_traits >::get() { + typedef std::vector container; + static container_identity identity(sizeof(container), &allocator_fn, + identity_traits::get()); + return &identity; + } + + template + container_identity *identity_traits >::get() { + typedef std::deque container; + static container_identity identity(sizeof(container), &allocator_fn, + identity_traits::get()); + return &identity; + } + + template + container_identity *identity_traits >::get() { + typedef BitArray container; + static type_identity *eid = identity_traits::get(); + static enum_identity *reid = eid->type() == DFHack::IDTYPE_ENUM ? (enum_identity*)eid : NULL; + static container_identity identity(sizeof(container), &allocator_fn, + &identity_traits::identity, reid); + return &identity; + } + + template + container_identity *identity_traits >::get() { + typedef DfArray container; + static container_identity identity(sizeof(container), &allocator_fn, + identity_traits::get()); + return &identity; + } +} + diff --git a/library/xml b/library/xml index 08e1f71e8..70eb6b5f3 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 08e1f71e89c1af6b3bef940914ed7f3d8fed89b0 +Subproject commit 70eb6b5f35680655d04d9fda79ff7251e21b45ae