diff options
Diffstat (limited to 'core/object.h')
-rw-r--r-- | core/object.h | 170 |
1 files changed, 89 insertions, 81 deletions
diff --git a/core/object.h b/core/object.h index 865c155764..b40aef2a42 100644 --- a/core/object.h +++ b/core/object.h @@ -34,8 +34,10 @@ #include "core/hash_map.h" #include "core/list.h" #include "core/map.h" +#include "core/object_id.h" #include "core/os/rw_lock.h" #include "core/set.h" +#include "core/spin_lock.h" #include "core/variant.h" #include "core/vmap.h" @@ -58,7 +60,6 @@ enum PropertyHint { PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc" PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) use "attenuation" hint string to revert (flip h), "full" to also include in/out. (ie: "attenuation,inout") PROPERTY_HINT_LENGTH, ///< hint_text= "length" (as integer) - PROPERTY_HINT_SPRITE_FRAME, // FIXME: Obsolete: drop whenever we can break compat. Keeping now for GDNative compat. PROPERTY_HINT_KEY_ACCEL, ///< hint_text= "length" (as integer) PROPERTY_HINT_FLAGS, ///< hint_text= "flag1,flag2,etc" (as bit flags) PROPERTY_HINT_LAYERS_2D_RENDER, @@ -89,6 +90,8 @@ enum PropertyHint { PROPERTY_HINT_OBJECT_TOO_BIG, ///< object is too big to send PROPERTY_HINT_NODE_PATH_VALID_TYPES, PROPERTY_HINT_SAVE_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,". This opens a save dialog + PROPERTY_HINT_INT_IS_OBJECTID, + PROPERTY_HINT_ARRAY_TYPE, PROPERTY_HINT_MAX, // When updating PropertyHint, also sync the hardcoded list in VisualScriptEditorVariableEdit }; @@ -104,10 +107,7 @@ enum PropertyUsageFlags { PROPERTY_USAGE_INTERNATIONALIZED = 64, //hint for internationalized strings PROPERTY_USAGE_GROUP = 128, //used for grouping props in the editor PROPERTY_USAGE_CATEGORY = 256, - // FIXME: Drop in 4.0, possibly reorder other flags? - // Those below are deprecated thanks to ClassDB's now class value cache - //PROPERTY_USAGE_STORE_IF_NONZERO = 512, //only store if nonzero - //PROPERTY_USAGE_STORE_IF_NONONE = 1024, //only store if false + PROPERTY_USAGE_SUBGROUP = 512, PROPERTY_USAGE_NO_INSTANCE_STATE = 2048, PROPERTY_USAGE_RESTART_IF_CHANGED = 4096, PROPERTY_USAGE_SCRIPT_VARIABLE = 8192, @@ -123,6 +123,7 @@ enum PropertyUsageFlags { PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT = 1 << 23, PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT = 1 << 24, PROPERTY_USAGE_KEYING_INCREMENTS = 1 << 25, // Used in inspector to increment property when keyed in animation player + PROPERTY_USAGE_DEFERRED_SET_RESOURCE = 1 << 26, // when loading, the resource for this property can be set at the end of loading PROPERTY_USAGE_DEFAULT = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK, PROPERTY_USAGE_DEFAULT_INTL = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK | PROPERTY_USAGE_INTERNATIONALIZED, @@ -134,6 +135,7 @@ enum PropertyUsageFlags { #define ADD_PROPERTYI(m_property, m_setter, m_getter, m_index) ClassDB::add_property(get_class_static(), m_property, _scs_create(m_setter), _scs_create(m_getter), m_index) #define ADD_PROPERTY_DEFAULT(m_property, m_default) ClassDB::set_property_default_value(get_class_static(), m_property, m_default) #define ADD_GROUP(m_name, m_prefix) ClassDB::add_property_group(get_class_static(), m_name, m_prefix) +#define ADD_SUBGROUP(m_name, m_prefix) ClassDB::add_property_subgroup(get_class_static(), m_name, m_prefix) struct PropertyInfo { @@ -238,7 +240,7 @@ struct MethodInfo { //if ( is_type(T::get_class_static()) ) //return static_cast<T*>(this); ////else -//return NULL; +//return nullptr; /* the following is an incomprehensible blob of hacks and workarounds to compensate for many of the fallencies in C++. As a plus, this macro pretty much alone defines the object model. @@ -397,7 +399,6 @@ public: \ private: class ScriptInstance; -typedef uint64_t ObjectID; class Object { public: @@ -411,18 +412,15 @@ public: struct Connection { - Object *source; - StringName signal; - Object *target; - StringName method; + ::Signal signal; + Callable callable; + uint32_t flags; Vector<Variant> binds; bool operator<(const Connection &p_conn) const; operator Variant() const; Connection() { - source = NULL; - target = NULL; flags = 0; } Connection(const Variant &p_variant); @@ -439,21 +437,7 @@ private: friend bool predelete_handler(Object *); friend void postinitialize_handler(Object *); - struct Signal { - - struct Target { - - ObjectID _id; - StringName method; - - _FORCE_INLINE_ bool operator<(const Target &p_target) const { return (_id == p_target._id) ? (method < p_target.method) : (_id < p_target._id); } - - Target(const ObjectID &p_id, const StringName &p_method) : - _id(p_id), - method(p_method) { - } - Target() { _id = 0; } - }; + struct SignalData { struct Slot { @@ -464,11 +448,11 @@ private: }; MethodInfo user; - VMap<Target, Slot> slot_map; - Signal() {} + VMap<Callable, Slot> slot_map; + SignalData() {} }; - HashMap<StringName, Signal> signal_map; + HashMap<StringName, SignalData> signal_map; List<Connection> connections; #ifdef DEBUG_ENABLED SafeRefCount _lock_index; @@ -487,14 +471,14 @@ private: Set<String> editor_section_folding; #endif ScriptInstance *script_instance; - RefPtr script; + Variant script; //reference does not yet exist, store it in a Dictionary metadata; mutable StringName _class_name; mutable const StringName *_class_ptr; void _add_user_signal(const String &p_name, const Array &p_args = Array()); bool _has_user_signal(const StringName &p_name) const; - Variant _emit_signal(const Variant **p_args, int p_argcount, Variant::CallError &r_error); + Variant _emit_signal(const Variant **p_args, int p_argcount, Callable::CallError &r_error); Array _get_signal_list() const; Array _get_signal_connection_list(const String &p_signal) const; Array _get_incoming_connections() const; @@ -505,9 +489,13 @@ private: void property_list_changed_notify(); + _FORCE_INLINE_ void _construct_object(bool p_reference); + friend class Reference; + bool type_is_reference = false; uint32_t instance_binding_count; void *_script_instance_bindings[MAX_SCRIPT_INSTANCE_BINDINGS]; + Object(bool p_reference); protected: virtual void _initialize_classv() { initialize_class(); } @@ -548,8 +536,8 @@ protected: //Variant _call_bind(const StringName& p_name, const Variant& p_arg1 = Variant(), const Variant& p_arg2 = Variant(), const Variant& p_arg3 = Variant(), const Variant& p_arg4 = Variant()); //void _call_deferred_bind(const StringName& p_name, const Variant& p_arg1 = Variant(), const Variant& p_arg2 = Variant(), const Variant& p_arg3 = Variant(), const Variant& p_arg4 = Variant()); - Variant _call_bind(const Variant **p_args, int p_argcount, Variant::CallError &r_error); - Variant _call_deferred_bind(const Variant **p_args, int p_argcount, Variant::CallError &r_error); + Variant _call_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error); + Variant _call_deferred_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error); virtual const StringName *_get_class_namev() const { if (!_class_name) @@ -557,7 +545,7 @@ protected: return &_class_name; } - PoolVector<String> _get_meta_list_bind() const; + Vector<String> _get_meta_list_bind() const; Array _get_property_list_bind() const; Array _get_method_list_bind() const; @@ -566,7 +554,7 @@ protected: friend class ClassDB; virtual void _validate_property(PropertyInfo &property) const; - void _disconnect(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method, bool p_force = false); + void _disconnect(const StringName &p_signal, const Callable &p_callable, bool p_force = false); public: //should be protected, but bug in clang++ static void initialize_class(); @@ -601,11 +589,11 @@ public: return dynamic_cast<T *>(p_object); #else if (!p_object) - return NULL; + return nullptr; if (p_object->is_class_ptr(T::get_class_ptr_static())) return static_cast<T *>(p_object); else - return NULL; + return nullptr; #endif } @@ -615,11 +603,11 @@ public: return dynamic_cast<const T *>(p_object); #else if (!p_object) - return NULL; + return nullptr; if (p_object->is_class_ptr(T::get_class_ptr_static())) return static_cast<const T *>(p_object); else - return NULL; + return nullptr; #endif } @@ -654,17 +642,17 @@ public: //void set(const String& p_name, const Variant& p_value); //Variant get(const String& p_name) const; - void set(const StringName &p_name, const Variant &p_value, bool *r_valid = NULL); - Variant get(const StringName &p_name, bool *r_valid = NULL) const; - void set_indexed(const Vector<StringName> &p_names, const Variant &p_value, bool *r_valid = NULL); - Variant get_indexed(const Vector<StringName> &p_names, bool *r_valid = NULL) const; + void set(const StringName &p_name, const Variant &p_value, bool *r_valid = nullptr); + Variant get(const StringName &p_name, bool *r_valid = nullptr) const; + void set_indexed(const Vector<StringName> &p_names, const Variant &p_value, bool *r_valid = nullptr); + Variant get_indexed(const Vector<StringName> &p_names, bool *r_valid = nullptr) const; void get_property_list(List<PropertyInfo> *p_list, bool p_reversed = false) const; bool has_method(const StringName &p_method) const; void get_method_list(List<MethodInfo> *p_list) const; Variant callv(const StringName &p_method, const Array &p_args); - virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error); + virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount); virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount); Variant call(const StringName &p_name, VARIANT_ARG_LIST); // C++ helper @@ -674,13 +662,13 @@ public: String to_string(); //used mainly by script, get and set all INCLUDING string - virtual Variant getvar(const Variant &p_key, bool *r_valid = NULL) const; - virtual void setvar(const Variant &p_key, const Variant &p_value, bool *r_valid = NULL); + virtual Variant getvar(const Variant &p_key, bool *r_valid = nullptr) const; + virtual void setvar(const Variant &p_key, const Variant &p_value, bool *r_valid = nullptr); /* SCRIPT */ - void set_script(const RefPtr &p_script); - RefPtr get_script() const; + void set_script(const Variant &p_script); + Variant get_script() const; /* SCRIPT */ @@ -699,20 +687,25 @@ public: void set_script_instance(ScriptInstance *p_instance); _FORCE_INLINE_ ScriptInstance *get_script_instance() const { return script_instance; } - void set_script_and_instance(const RefPtr &p_script, ScriptInstance *p_instance); //some script languages can't control instance creation, so this function eases the process + void set_script_and_instance(const Variant &p_script, ScriptInstance *p_instance); //some script languages can't control instance creation, so this function eases the process void add_user_signal(const MethodInfo &p_signal); Error emit_signal(const StringName &p_name, VARIANT_ARG_LIST); Error emit_signal(const StringName &p_name, const Variant **p_args, int p_argcount); + bool has_signal(const StringName &p_name) const; void get_signal_list(List<MethodInfo> *p_signals) const; void get_signal_connection_list(const StringName &p_signal, List<Connection> *p_connections) const; void get_all_signal_connections(List<Connection> *p_connections) const; int get_persistent_signal_connection_count() const; void get_signals_connected_to_this(List<Connection> *p_connections) const; - Error connect(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method, const Vector<Variant> &p_binds = Vector<Variant>(), uint32_t p_flags = 0); - void disconnect(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method); - bool is_connected(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method) const; + Error connect_compat(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method, const Vector<Variant> &p_binds = Vector<Variant>(), uint32_t p_flags = 0); + void disconnect_compat(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method); + bool is_connected_compat(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method) const; + + Error connect(const StringName &p_signal, const Callable &p_callable, const Vector<Variant> &p_binds = Vector<Variant>(), uint32_t p_flags = 0); + void disconnect(const StringName &p_signal, const Callable &p_callable); + bool is_connected(const StringName &p_signal, const Callable &p_callable) const; void call_deferred(const StringName &p_method, VARIANT_ARG_LIST); void set_deferred(const StringName &p_property, const Variant &p_value); @@ -720,8 +713,8 @@ public: void set_block_signals(bool p_block); bool is_blocking_signals() const; - Variant::Type get_static_property_type(const StringName &p_property, bool *r_valid = NULL) const; - Variant::Type get_static_property_type_indexed(const Vector<StringName> &p_path, bool *r_valid = NULL) const; + Variant::Type get_static_property_type(const StringName &p_property, bool *r_valid = nullptr) const; + Variant::Type get_static_property_type_indexed(const Vector<StringName> &p_path, bool *r_valid = nullptr) const; virtual void get_translatable_strings(List<String> *p_strings) const; @@ -750,6 +743,7 @@ public: void clear_internal_resource_paths(); + _ALWAYS_INLINE_ bool is_reference() const { return type_is_reference; } Object(); virtual ~Object(); }; @@ -759,52 +753,66 @@ 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); - } +//this needs to add up to 63, 1 bit is for reference +#define OBJECTDB_VALIDATOR_BITS 39 +#define OBJECTDB_VALIDATOR_MASK ((uint64_t(1) << OBJECTDB_VALIDATOR_BITS) - 1) +#define OBJECTDB_SLOT_MAX_COUNT_BITS 24 +#define OBJECTDB_SLOT_MAX_COUNT_MASK ((uint64_t(1) << OBJECTDB_SLOT_MAX_COUNT_BITS) - 1) +#define OBJECTDB_REFERENCE_BIT (uint64_t(1) << (OBJECTDB_SLOT_MAX_COUNT_BITS + OBJECTDB_VALIDATOR_BITS)) + + struct ObjectSlot { //128 bits per slot + uint64_t validator : OBJECTDB_VALIDATOR_BITS; + uint64_t next_free : OBJECTDB_SLOT_MAX_COUNT_BITS; + uint64_t is_reference : 1; + Object *object; }; - static HashMap<ObjectID, Object *> instances; - static HashMap<Object *, ObjectID, ObjectPtrHash> instance_checks; + static SpinLock spin_lock; + static uint32_t slot_count; + static uint32_t slot_max; + static ObjectSlot *object_slots; + static uint64_t validator_counter; - 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(); static void setup(); 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(); + _ALWAYS_INLINE_ static Object *get_instance(ObjectID p_instance_id) { + + uint64_t id = p_instance_id; + uint32_t slot = id & OBJECTDB_SLOT_MAX_COUNT_MASK; + + ERR_FAIL_COND_V(slot >= slot_max, nullptr); //this should never happen unless RID is corrupted - _FORCE_INLINE_ static bool instance_validate(Object *p_ptr) { - rw_lock->read_lock(); + spin_lock.lock(); - bool exists = instance_checks.has(p_ptr); + uint64_t validator = (id >> OBJECTDB_SLOT_MAX_COUNT_BITS) & OBJECTDB_VALIDATOR_MASK; - rw_lock->read_unlock(); + if (unlikely(object_slots[slot].validator != validator)) { + spin_lock.unlock(); + return nullptr; + } + + Object *object = object_slots[slot].object; + + spin_lock.unlock(); - return exists; + return object; } + static void debug_objects(DebugFunc p_func); + static int get_object_count(); }; //needed by macros #include "core/class_db.h" -#endif +#endif // OBJECT_H |