mirror of
https://github.com/Relintai/sfw.git
synced 2024-11-08 07:52:09 +01:00
Grab some goodies for Object from pandemonium. Also init MemoryPool and StringNames.
This commit is contained in:
parent
533dadacef
commit
c6f3a8b245
10
main.cpp
10
main.cpp
@ -8,6 +8,9 @@
|
|||||||
#include "game_application.h"
|
#include "game_application.h"
|
||||||
#include "render_core/window.h"
|
#include "render_core/window.h"
|
||||||
|
|
||||||
|
#include "core/pool_vector.h"
|
||||||
|
#include "core/string_name.h"
|
||||||
|
|
||||||
Application *application = NULL;
|
Application *application = NULL;
|
||||||
|
|
||||||
void handle_frame() {
|
void handle_frame() {
|
||||||
@ -15,6 +18,10 @@ void handle_frame() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
|
//TODO centralize these
|
||||||
|
StringName::setup();
|
||||||
|
MemoryPool::setup();
|
||||||
|
|
||||||
AppWindow *w = memnew(AppWindow());
|
AppWindow *w = memnew(AppWindow());
|
||||||
w->create(100, 0);
|
w->create(100, 0);
|
||||||
|
|
||||||
@ -43,5 +50,8 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
#endif // __EMSCRIPTEN__
|
#endif // __EMSCRIPTEN__
|
||||||
|
|
||||||
|
StringName::cleanup();
|
||||||
|
MemoryPool::cleanup();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -71,8 +71,6 @@ class StringName {
|
|||||||
friend void unregister_core_types();
|
friend void unregister_core_types();
|
||||||
|
|
||||||
static Mutex lock;
|
static Mutex lock;
|
||||||
static void setup();
|
|
||||||
static void cleanup();
|
|
||||||
static bool configured;
|
static bool configured;
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
struct DebugSortReferences {
|
struct DebugSortReferences {
|
||||||
@ -177,6 +175,9 @@ public:
|
|||||||
unref();
|
unref();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void setup();
|
||||||
|
static void cleanup();
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1,8 +1,169 @@
|
|||||||
#include "object/object.h"
|
#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() {
|
Object::Object() {
|
||||||
|
_is_queued_for_deletion = false;
|
||||||
|
_predelete_ok = 0;
|
||||||
|
_instance_id = 0;
|
||||||
|
_instance_id = ObjectDB::add_instance(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object::~Object() {
|
Object::~Object() {
|
||||||
|
}
|
||||||
|
|
||||||
}
|
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<ObjectRC *>(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<ObjectID, Object *> ObjectDB::instances;
|
||||||
|
ObjectID ObjectDB::instance_counter = 1;
|
||||||
|
HashMap<Object *, ObjectID, ObjectDB::ObjectPtrHash> 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();
|
||||||
|
}
|
||||||
|
@ -1,15 +1,23 @@
|
|||||||
#ifndef OBJECT_H
|
#ifndef OBJECT_H
|
||||||
#define 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/ustring.h"
|
||||||
#include "core/vector.h"
|
#include "core/vector.h"
|
||||||
|
#include "object/object_id.h"
|
||||||
|
|
||||||
|
//#include "object/dictionary.h"
|
||||||
|
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
/* object.h */
|
/* object.h */
|
||||||
/* From https://github.com/Relintai/pandemonium_engine (MIT) */
|
/* 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: \
|
private: \
|
||||||
void operator=(const m_class &p_rval) {} \
|
void operator=(const m_class &p_rval) {} \
|
||||||
\
|
\
|
||||||
@ -17,6 +25,11 @@ public:
|
|||||||
virtual String get_class() const override { \
|
virtual String get_class() const override { \
|
||||||
return String(#m_class); \
|
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 void *get_class_ptr_static() { \
|
||||||
static int ptr; \
|
static int ptr; \
|
||||||
return &ptr; \
|
return &ptr; \
|
||||||
@ -40,19 +53,34 @@ public:
|
|||||||
virtual bool is_class_ptr(void *p_ptr) const override { \
|
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); \
|
return (p_ptr == get_class_ptr_static()) ? true : m_inherits::is_class_ptr(p_ptr); \
|
||||||
} \
|
} \
|
||||||
\
|
|
||||||
static void get_valid_parents_static(Vector<String> *p_parents) { \
|
static void get_valid_parents_static(Vector<String> *p_parents) { \
|
||||||
if (m_class::_get_valid_parents_static != m_inherits::_get_valid_parents_static) { \
|
if (m_class::_get_valid_parents_static != m_inherits::_get_valid_parents_static) { \
|
||||||
m_class::_get_valid_parents_static(p_parents); \
|
m_class::_get_valid_parents_static(p_parents); \
|
||||||
} \
|
} \
|
||||||
\
|
|
||||||
m_inherits::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:
|
private:
|
||||||
|
|
||||||
class Object {
|
class Object {
|
||||||
public:
|
public:
|
||||||
|
enum {
|
||||||
|
NOTIFICATION_POSTINITIALIZE = 0,
|
||||||
|
NOTIFICATION_PREDELETE = 1
|
||||||
|
};
|
||||||
|
|
||||||
virtual String get_class() const { return "Object"; }
|
virtual String get_class() const { return "Object"; }
|
||||||
static void *get_class_ptr_static() {
|
static void *get_class_ptr_static() {
|
||||||
static int ptr;
|
static int ptr;
|
||||||
@ -70,6 +98,45 @@ public:
|
|||||||
static void get_valid_parents_static(Vector<String> *p_parents) {}
|
static void get_valid_parents_static(Vector<String> *p_parents) {}
|
||||||
static void _get_valid_parents_static(Vector<String> *p_parents) {}
|
static void _get_valid_parents_static(Vector<String> *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<String> *p_list) const;
|
||||||
|
*/
|
||||||
|
|
||||||
Object();
|
Object();
|
||||||
virtual ~Object();
|
virtual ~Object();
|
||||||
|
|
||||||
@ -92,6 +159,76 @@ public:
|
|||||||
else
|
else
|
||||||
return NULL;
|
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<ObjectRC *> _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<ObjectID, Object *> instances;
|
||||||
|
static HashMap<Object *, ObjectID, ObjectPtrHash> 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
|
#endif
|
Loading…
Reference in New Issue
Block a user