From c6f3a8b245ebb4676d5942d3b2ab8a0cb4e53e0b Mon Sep 17 00:00:00 2001 From: Relintai Date: Sun, 31 Dec 2023 16:20:14 +0100 Subject: [PATCH] Grab some goodies for Object from pandemonium. Also init MemoryPool and StringNames. --- main.cpp | 10 +++ sfw/core/string_name.h | 5 +- sfw/object/object.cpp | 163 ++++++++++++++++++++++++++++++++++++++++- sfw/object/object.h | 143 +++++++++++++++++++++++++++++++++++- 4 files changed, 315 insertions(+), 6 deletions(-) diff --git a/main.cpp b/main.cpp index 8ca110e..0088989 100644 --- a/main.cpp +++ b/main.cpp @@ -8,6 +8,9 @@ #include "game_application.h" #include "render_core/window.h" +#include "core/pool_vector.h" +#include "core/string_name.h" + Application *application = NULL; void handle_frame() { @@ -15,6 +18,10 @@ void handle_frame() { } int main(int argc, char **argv) { + //TODO centralize these + StringName::setup(); + MemoryPool::setup(); + AppWindow *w = memnew(AppWindow()); w->create(100, 0); @@ -43,5 +50,8 @@ int main(int argc, char **argv) { #endif // __EMSCRIPTEN__ + StringName::cleanup(); + MemoryPool::cleanup(); + return 0; } diff --git a/sfw/core/string_name.h b/sfw/core/string_name.h index eb55a8c..8f97676 100644 --- a/sfw/core/string_name.h +++ b/sfw/core/string_name.h @@ -71,8 +71,6 @@ class StringName { friend void unregister_core_types(); static Mutex lock; - static void setup(); - static void cleanup(); static bool configured; #ifdef DEBUG_ENABLED struct DebugSortReferences { @@ -177,6 +175,9 @@ public: unref(); } } + + static void setup(); + static void cleanup(); }; /* diff --git a/sfw/object/object.cpp b/sfw/object/object.cpp index 194e03d..3c4bb0e 100644 --- a/sfw/object/object.cpp +++ b/sfw/object/object.cpp @@ -1,8 +1,169 @@ #include "object/object.h" +#include "core/error_macros.h" +#include "core/logger.h" +#include "object/object_rc.h" + +void Object::notification(int p_notification, bool p_reversed) { + _notificationv(p_notification, p_reversed); +} + +String Object::to_string() { + return "[" + get_class() + ":" + itos(get_instance_id()) + "]"; +} + +bool Object::_predelete() { + _predelete_ok = 1; + notification(NOTIFICATION_PREDELETE, true); + if (_predelete_ok) { + _class_ptr = nullptr; //must restore so destructors can access class ptr correctly + } + return _predelete_ok; +} + +void Object::_postinitialize() { + _class_ptr = _get_class_namev(); + notification(NOTIFICATION_POSTINITIALIZE); +} + +/* +bool Object::has_meta(const String &p_name) const { + return metadata.has(p_name); +} + +void Object::set_meta(const String &p_name, const Variant &p_value) { + if (p_value.get_type() == Variant::NIL) { + metadata.erase(p_name); + return; + }; + + metadata[p_name] = p_value; +} + +Variant Object::get_meta(const String &p_name, const Variant &p_default) const { + if (!metadata.has(p_name)) { + return p_default; + } + return metadata[p_name]; +} + +void Object::remove_meta(const String &p_name) { + metadata.erase(p_name); +} +*/ + +void Object::cancel_free() { + _predelete_ok = 0; +} + Object::Object() { + _is_queued_for_deletion = false; + _predelete_ok = 0; + _instance_id = 0; + _instance_id = ObjectDB::add_instance(this); } Object::~Object() { +} -} \ No newline at end of file +ObjectRC *Object::_use_rc() { + // The RC object is lazily created the first time it's requested; + // that way, there's no need to allocate and release it at all if this Object + // is not being referred by any Variant at all. + + // Although when dealing with Objects from multiple threads some locking + // mechanism should be used, this at least makes safe the case of first + // assignment. + + ObjectRC *rc = nullptr; + ObjectRC *const creating = reinterpret_cast(1); + if (unlikely(_rc.compare_exchange_strong(rc, creating, std::memory_order_acq_rel))) { + // Not created yet + rc = memnew(ObjectRC(this)); + _rc.store(rc, std::memory_order_release); + return rc; + } + + // Spin-wait until we know it's created (or just return if it's already created) + for (;;) { + if (likely(rc != creating)) { + rc->increment(); + return rc; + } + rc = _rc.load(std::memory_order_acquire); + } +} + +bool predelete_handler(Object *p_object) { + return p_object->_predelete(); +} + +void postinitialize_handler(Object *p_object) { + p_object->_postinitialize(); +} + +HashMap ObjectDB::instances; +ObjectID ObjectDB::instance_counter = 1; +HashMap ObjectDB::instance_checks; +ObjectID ObjectDB::add_instance(Object *p_object) { + ERR_FAIL_COND_V(p_object->get_instance_id() != 0, 0); + + rw_lock.write_lock(); + ObjectID instance_id = ++instance_counter; + instances[instance_id] = p_object; + instance_checks[p_object] = instance_id; + + rw_lock.write_unlock(); + + return instance_id; +} + +void ObjectDB::remove_instance(Object *p_object) { + rw_lock.write_lock(); + + instances.erase(p_object->get_instance_id()); + instance_checks.erase(p_object); + + rw_lock.write_unlock(); +} +Object *ObjectDB::get_instance(ObjectID p_instance_id) { + rw_lock.read_lock(); + Object **obj = instances.getptr(p_instance_id); + rw_lock.read_unlock(); + + if (!obj) { + return nullptr; + } + return *obj; +} + +void ObjectDB::debug_objects(DebugFunc p_func) { + rw_lock.read_lock(); + + const ObjectID *K = nullptr; + while ((K = instances.next(K))) { + p_func(instances[*K]); + } + + rw_lock.read_unlock(); +} + +int ObjectDB::get_object_count() { + rw_lock.read_lock(); + int count = instances.size(); + rw_lock.read_unlock(); + + return count; +} + +RWLock ObjectDB::rw_lock; + +void ObjectDB::cleanup() { + rw_lock.write_lock(); + if (instances.size()) { + LOG_WARN("ObjectDB instances leaked at exit!"); + } + instances.clear(); + instance_checks.clear(); + rw_lock.write_unlock(); +} diff --git a/sfw/object/object.h b/sfw/object/object.h index ead8220..59719f5 100644 --- a/sfw/object/object.h +++ b/sfw/object/object.h @@ -1,15 +1,23 @@ #ifndef OBJECT_H #define OBJECT_H +#include "core/hash_map.h" +#include "core/rw_lock.h" +#include "core/string_name.h" #include "core/ustring.h" #include "core/vector.h" +#include "object/object_id.h" + +//#include "object/dictionary.h" /*************************************************************************/ /* object.h */ /* From https://github.com/Relintai/pandemonium_engine (MIT) */ /*************************************************************************/ -#define SFW_OBJECT(m_class, m_inherits) \ +class ObjectRC; + +#define SFW_OBJECT(m_class, m_inherits) \ private: \ void operator=(const m_class &p_rval) {} \ \ @@ -17,6 +25,11 @@ public: virtual String get_class() const override { \ return String(#m_class); \ } \ + virtual const StringName *_get_class_namev() const { \ + if (!_class_name) \ + _class_name = get_class_static(); \ + return &_class_name; \ + } \ static void *get_class_ptr_static() { \ static int ptr; \ return &ptr; \ @@ -40,19 +53,34 @@ public: virtual bool is_class_ptr(void *p_ptr) const override { \ return (p_ptr == get_class_ptr_static()) ? true : m_inherits::is_class_ptr(p_ptr); \ } \ - \ static void get_valid_parents_static(Vector *p_parents) { \ if (m_class::_get_valid_parents_static != m_inherits::_get_valid_parents_static) { \ m_class::_get_valid_parents_static(p_parents); \ } \ - \ m_inherits::get_valid_parents_static(p_parents); \ + } \ + _FORCE_INLINE_ void (Object::*_get_notification() const)(int) { \ + return (void(Object::*)(int)) & m_class::_notification; \ + } \ + virtual void _notificationv(int p_notification, bool p_reversed) { \ + if (!p_reversed) \ + m_inherits::_notificationv(p_notification, p_reversed); \ + if (m_class::_get_notification() != m_inherits::_get_notification()) { \ + _notification(p_notification); \ + } \ + if (p_reversed) \ + m_inherits::_notificationv(p_notification, p_reversed); \ } \ \ private: class Object { public: + enum { + NOTIFICATION_POSTINITIALIZE = 0, + NOTIFICATION_PREDELETE = 1 + }; + virtual String get_class() const { return "Object"; } static void *get_class_ptr_static() { static int ptr; @@ -70,6 +98,45 @@ public: static void get_valid_parents_static(Vector *p_parents) {} static void _get_valid_parents_static(Vector *p_parents) {} + virtual const StringName *_get_class_namev() const { + if (!_class_name) { + _class_name = get_class_static(); + } + return &_class_name; + } + + _FORCE_INLINE_ const StringName &get_class_name() const { + if (!_class_ptr) { + return *_get_class_namev(); + } else { + return *_class_ptr; + } + } + + ObjectRC *_use_rc(); + + _FORCE_INLINE_ ObjectID get_instance_id() const { + return _instance_id; + } + + void notification(int p_notification, bool p_reversed = false); + virtual String to_string(); + + bool _is_queued_for_deletion; + bool is_queued_for_deletion() const { + return _is_queued_for_deletion; + } + + void cancel_free(); + + /* + bool has_meta(const String &p_name) const; + void set_meta(const String &p_name, const Variant &p_value); + void remove_meta(const String &p_name); + Variant get_meta(const String &p_name, const Variant &p_default = Variant()) const; + void get_meta_list(List *p_list) const; + */ + Object(); virtual ~Object(); @@ -92,6 +159,76 @@ public: else return NULL; } + +protected: + _FORCE_INLINE_ void (Object::*_get_notification() const)(int) { + return &Object::_notification; + } + + virtual void _notificationv(int p_notification, bool p_reversed){}; + void _notification(int p_notification){}; + + friend bool predelete_handler(Object *); + friend void postinitialize_handler(Object *); + + int _predelete_ok; + bool _predelete(); + void _postinitialize(); + + mutable StringName _class_name; + mutable const StringName *_class_ptr; + + ObjectID _instance_id; + std::atomic _rc; + + //Dictionary metadata; +}; + +bool predelete_handler(Object *p_object); +void postinitialize_handler(Object *p_object); + +class ObjectDB { + struct ObjectPtrHash { + static _FORCE_INLINE_ uint32_t hash(const Object *p_obj) { + union { + const Object *p; + unsigned long i; + } u; + u.p = p_obj; + return HashMapHasherDefault::hash((uint64_t)u.i); + } + }; + + static HashMap instances; + static HashMap instance_checks; + + static ObjectID instance_counter; + friend class Object; + friend void unregister_core_types(); + + static RWLock rw_lock; + static void cleanup(); + static ObjectID add_instance(Object *p_object); + static void remove_instance(Object *p_object); + friend void register_core_types(); + +public: + typedef void (*DebugFunc)(Object *p_obj); + + static Object *get_instance(ObjectID p_instance_id); + static void debug_objects(DebugFunc p_func); + static int get_object_count(); + + // This one may give false positives because a new object may be allocated at the same memory of a previously freed one + _FORCE_INLINE_ static bool instance_validate(Object *p_ptr) { + rw_lock.read_lock(); + + bool exists = instance_checks.has(p_ptr); + + rw_lock.read_unlock(); + + return exists; + } }; #endif \ No newline at end of file