mirror of
https://github.com/godotengine/godot.git
synced 2025-10-19 16:03:29 +00:00
Add GDType
and Object::_gdtype_ptr
for first-class Object
typing.
The type is currently bare-bones, but will be expanded in future PRs.
This commit is contained in:
parent
d705613db3
commit
ac85d24e64
4 changed files with 151 additions and 47 deletions
42
core/object/gdtype.cpp
Normal file
42
core/object/gdtype.cpp
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/**************************************************************************/
|
||||||
|
/* gdtype.cpp */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||||
|
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#include "gdtype.h"
|
||||||
|
|
||||||
|
GDType::GDType(const GDType *p_super_type, StringName p_name) :
|
||||||
|
super_type(p_super_type), name(std::move(p_name)) {
|
||||||
|
name_hierarchy.push_back(StringName(name, true));
|
||||||
|
|
||||||
|
if (super_type) {
|
||||||
|
for (const StringName &ancestor_name : super_type->name_hierarchy) {
|
||||||
|
name_hierarchy.push_back(StringName(ancestor_name, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
50
core/object/gdtype.h
Normal file
50
core/object/gdtype.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/**************************************************************************/
|
||||||
|
/* gdtype.h */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||||
|
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/string/string_name.h"
|
||||||
|
#include "core/templates/vector.h"
|
||||||
|
|
||||||
|
class GDType {
|
||||||
|
const GDType *super_type;
|
||||||
|
|
||||||
|
StringName name;
|
||||||
|
/// Contains all the class names in order:
|
||||||
|
/// `name` is the first element and `Object` is the last.
|
||||||
|
Vector<StringName> name_hierarchy;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GDType(const GDType *p_super_type, StringName p_name);
|
||||||
|
|
||||||
|
const GDType *get_super_type() const { return super_type; }
|
||||||
|
const StringName &get_name() const { return name; }
|
||||||
|
const Vector<StringName> &get_name_hierarchy() const { return name_hierarchy; }
|
||||||
|
};
|
|
@ -258,7 +258,7 @@ bool Object::_predelete() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_class_name_ptr = nullptr; // Must restore, so constructors/destructors have proper class name access at each stage.
|
_gdtype_ptr = nullptr; // Must restore, so constructors/destructors have proper class name access at each stage.
|
||||||
notification(NOTIFICATION_PREDELETE_CLEANUP, true);
|
notification(NOTIFICATION_PREDELETE_CLEANUP, true);
|
||||||
|
|
||||||
// Destruction order starts with the most derived class, and progresses towards the base Object class:
|
// Destruction order starts with the most derived class, and progresses towards the base Object class:
|
||||||
|
@ -301,7 +301,7 @@ void Object::cancel_free() {
|
||||||
|
|
||||||
void Object::_initialize() {
|
void Object::_initialize() {
|
||||||
// Cache the class name in the object for quick reference.
|
// Cache the class name in the object for quick reference.
|
||||||
_class_name_ptr = _get_class_namev();
|
_gdtype_ptr = &_get_typev();
|
||||||
_initialize_classv();
|
_initialize_classv();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2085,18 +2085,34 @@ uint32_t Object::get_edited_version() const {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
const GDType &Object::get_gdtype() const {
|
||||||
|
if (unlikely(!_gdtype_ptr)) {
|
||||||
|
// While class is initializing / deinitializing, constructors and destructors
|
||||||
|
// need access to the proper type at the proper stage.
|
||||||
|
return _get_typev();
|
||||||
|
}
|
||||||
|
return *_gdtype_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Object::is_class(const String &p_class) const {
|
||||||
|
if (_extension && _extension->is_class(p_class)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (const StringName &name : get_gdtype().get_name_hierarchy()) {
|
||||||
|
if (name == p_class) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const StringName &Object::get_class_name() const {
|
const StringName &Object::get_class_name() const {
|
||||||
if (_extension) {
|
if (_extension) {
|
||||||
// Can't put inside the unlikely as constructor can run it.
|
// Can't put inside the unlikely as constructor can run it.
|
||||||
return _extension->class_name;
|
return _extension->class_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(!_class_name_ptr)) {
|
return get_gdtype().get_name();
|
||||||
// While class is initializing / deinitializing, constructors and destructors
|
|
||||||
// need access to the proper class at the proper stage.
|
|
||||||
return *_get_class_namev();
|
|
||||||
}
|
|
||||||
return *_class_name_ptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StringName Object::get_class_name_for_extension(const GDExtension *p_library) const {
|
StringName Object::get_class_name_for_extension(const GDExtension *p_library) const {
|
||||||
|
@ -2105,8 +2121,7 @@ StringName Object::get_class_name_for_extension(const GDExtension *p_library) co
|
||||||
// have to return the closest native parent's class name, so that it doesn't try to
|
// have to return the closest native parent's class name, so that it doesn't try to
|
||||||
// use this like the real object.
|
// use this like the real object.
|
||||||
if (unlikely(_extension && _extension->library == p_library && _extension->is_placeholder)) {
|
if (unlikely(_extension && _extension->library == p_library && _extension->is_placeholder)) {
|
||||||
const StringName *class_name = _get_class_namev();
|
return get_class_name();
|
||||||
return *class_name;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -2116,13 +2131,13 @@ StringName Object::get_class_name_for_extension(const GDExtension *p_library) co
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extensions only have wrapper classes for classes exposed in ClassDB.
|
// Extensions only have wrapper classes for classes exposed in ClassDB.
|
||||||
const StringName *class_name = _get_class_namev();
|
const StringName &class_name = get_class_name();
|
||||||
if (ClassDB::is_class_exposed(*class_name)) {
|
if (ClassDB::is_class_exposed(class_name)) {
|
||||||
return *class_name;
|
return class_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the nearest parent class that's exposed.
|
// Find the nearest parent class that's exposed.
|
||||||
StringName parent_class = ClassDB::get_parent_class(*class_name);
|
StringName parent_class = ClassDB::get_parent_class(class_name);
|
||||||
while (parent_class != StringName()) {
|
while (parent_class != StringName()) {
|
||||||
if (ClassDB::is_class_exposed(parent_class)) {
|
if (ClassDB::is_class_exposed(parent_class)) {
|
||||||
return parent_class;
|
return parent_class;
|
||||||
|
@ -2296,14 +2311,16 @@ void Object::detach_from_objectdb() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::assign_class_name_static(const Span<char> &p_name, StringName &r_target) {
|
void Object::assign_type_static(GDType **type_ptr, const char *p_name, const GDType *super_type) {
|
||||||
static BinaryMutex _mutex;
|
static BinaryMutex _mutex;
|
||||||
MutexLock lock(_mutex);
|
MutexLock lock(_mutex);
|
||||||
if (r_target) {
|
GDType *type = *type_ptr;
|
||||||
// Already assigned while we were waiting for the mutex.
|
if (type) {
|
||||||
|
// Assigned while we were waiting.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
r_target = StringName(p_name.ptr(), true);
|
type = memnew(GDType(super_type, StringName(p_name, true)));
|
||||||
|
*type_ptr = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object::~Object() {
|
Object::~Object() {
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "core/extension/gdextension_interface.h"
|
#include "core/extension/gdextension_interface.h"
|
||||||
|
#include "core/object/gdtype.h"
|
||||||
#include "core/object/message_queue.h"
|
#include "core/object/message_queue.h"
|
||||||
#include "core/object/object_id.h"
|
#include "core/object/object_id.h"
|
||||||
#include "core/os/rw_lock.h"
|
#include "core/os/rw_lock.h"
|
||||||
|
@ -494,21 +495,18 @@ private:
|
||||||
friend class ::ClassDB; \
|
friend class ::ClassDB; \
|
||||||
\
|
\
|
||||||
public: \
|
public: \
|
||||||
virtual const StringName *_get_class_namev() const override { \
|
virtual const GDType &_get_typev() const override { \
|
||||||
return &get_class_static(); \
|
return get_gdtype_static(); \
|
||||||
|
} \
|
||||||
|
static const GDType &get_gdtype_static() { \
|
||||||
|
static GDType *_class_static; \
|
||||||
|
if (unlikely(!_class_static)) { \
|
||||||
|
assign_type_static(&_class_static, #m_class, &super_type::get_gdtype_static()); \
|
||||||
|
} \
|
||||||
|
return *_class_static; \
|
||||||
} \
|
} \
|
||||||
static const StringName &get_class_static() { \
|
static const StringName &get_class_static() { \
|
||||||
static StringName _class_name_static; \
|
return get_gdtype_static().get_name(); \
|
||||||
if (unlikely(!_class_name_static)) { \
|
|
||||||
assign_class_name_static(#m_class, _class_name_static); \
|
|
||||||
} \
|
|
||||||
return _class_name_static; \
|
|
||||||
} \
|
|
||||||
virtual bool is_class(const String &p_class) const override { \
|
|
||||||
if (_get_extension() && _get_extension()->is_class(p_class)) { \
|
|
||||||
return true; \
|
|
||||||
} \
|
|
||||||
return (p_class == (#m_class)) ? true : m_inherits::is_class(p_class); \
|
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
protected: \
|
protected: \
|
||||||
|
@ -668,7 +666,7 @@ private:
|
||||||
Variant script; // Reference does not exist yet, store it in a Variant.
|
Variant script; // Reference does not exist yet, store it in a Variant.
|
||||||
HashMap<StringName, Variant> metadata;
|
HashMap<StringName, Variant> metadata;
|
||||||
HashMap<StringName, Variant *> metadata_properties;
|
HashMap<StringName, Variant *> metadata_properties;
|
||||||
mutable const StringName *_class_name_ptr = nullptr;
|
mutable const GDType *_gdtype_ptr = nullptr;
|
||||||
|
|
||||||
void _add_user_signal(const String &p_name, const Array &p_args = Array());
|
void _add_user_signal(const String &p_name, const Array &p_args = Array());
|
||||||
bool _has_user_signal(const StringName &p_name) const;
|
bool _has_user_signal(const StringName &p_name) const;
|
||||||
|
@ -774,9 +772,7 @@ protected:
|
||||||
Variant _call_bind(const Variant **p_args, int p_argcount, Callable::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);
|
Variant _call_deferred_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
|
||||||
|
|
||||||
virtual const StringName *_get_class_namev() const {
|
virtual const GDType &_get_typev() const { return get_gdtype_static(); }
|
||||||
return &get_class_static();
|
|
||||||
}
|
|
||||||
|
|
||||||
TypedArray<StringName> _get_meta_list_bind() const;
|
TypedArray<StringName> _get_meta_list_bind() const;
|
||||||
TypedArray<Dictionary> _get_property_list_bind() const;
|
TypedArray<Dictionary> _get_property_list_bind() const;
|
||||||
|
@ -842,26 +838,25 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
/* TYPE API */
|
/* TYPE API */
|
||||||
static void assign_class_name_static(const Span<char> &p_name, StringName &r_target);
|
static void assign_type_static(GDType **type_ptr, const char *p_name, const GDType *super_type);
|
||||||
|
|
||||||
static const StringName &get_class_static() {
|
static const GDType &get_gdtype_static() {
|
||||||
static StringName _class_name_static;
|
static GDType *_class_static;
|
||||||
if (unlikely(!_class_name_static)) {
|
if (unlikely(!_class_static)) {
|
||||||
assign_class_name_static("Object", _class_name_static);
|
assign_type_static(&_class_static, "Object", nullptr);
|
||||||
}
|
}
|
||||||
return _class_name_static;
|
return *_class_static;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const GDType &get_gdtype() const;
|
||||||
|
|
||||||
|
static const StringName &get_class_static() { return get_gdtype_static().get_name(); }
|
||||||
|
|
||||||
_FORCE_INLINE_ String get_class() const { return get_class_name(); }
|
_FORCE_INLINE_ String get_class() const { return get_class_name(); }
|
||||||
|
|
||||||
virtual String get_save_class() const { return get_class(); } //class stored when saving
|
virtual String get_save_class() const { return get_class(); } //class stored when saving
|
||||||
|
|
||||||
virtual bool is_class(const String &p_class) const {
|
bool is_class(const String &p_class) const;
|
||||||
if (_extension && _extension->is_class(p_class)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return (p_class == "Object");
|
|
||||||
}
|
|
||||||
virtual bool is_class_ptr(void *p_ptr) const { return get_class_ptr_static() == p_ptr; }
|
virtual bool is_class_ptr(void *p_ptr) const { return get_class_ptr_static() == p_ptr; }
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue