Skip to content

Commit dd6ffaa

Browse files
committed
Merge pull request godotengine#105793 from Ivorforce/gdtype-the-first
Core: Add initial architecture for first-class `Object` types. Optimize `is_class`
2 parents e8535bc + ac85d24 commit dd6ffaa

File tree

4 files changed

+150
-46
lines changed

4 files changed

+150
-46
lines changed

core/object/gdtype.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**************************************************************************/
2+
/* gdtype.cpp */
3+
/**************************************************************************/
4+
/* This file is part of: */
5+
/* GODOT ENGINE */
6+
/* https://godotengine.org */
7+
/**************************************************************************/
8+
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9+
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10+
/* */
11+
/* Permission is hereby granted, free of charge, to any person obtaining */
12+
/* a copy of this software and associated documentation files (the */
13+
/* "Software"), to deal in the Software without restriction, including */
14+
/* without limitation the rights to use, copy, modify, merge, publish, */
15+
/* distribute, sublicense, and/or sell copies of the Software, and to */
16+
/* permit persons to whom the Software is furnished to do so, subject to */
17+
/* the following conditions: */
18+
/* */
19+
/* The above copyright notice and this permission notice shall be */
20+
/* included in all copies or substantial portions of the Software. */
21+
/* */
22+
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23+
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24+
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25+
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26+
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27+
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28+
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29+
/**************************************************************************/
30+
31+
#include "gdtype.h"
32+
33+
GDType::GDType(const GDType *p_super_type, StringName p_name) :
34+
super_type(p_super_type), name(std::move(p_name)) {
35+
name_hierarchy.push_back(StringName(name, true));
36+
37+
if (super_type) {
38+
for (const StringName &ancestor_name : super_type->name_hierarchy) {
39+
name_hierarchy.push_back(StringName(ancestor_name, true));
40+
}
41+
}
42+
}

core/object/gdtype.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/**************************************************************************/
2+
/* gdtype.h */
3+
/**************************************************************************/
4+
/* This file is part of: */
5+
/* GODOT ENGINE */
6+
/* https://godotengine.org */
7+
/**************************************************************************/
8+
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9+
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10+
/* */
11+
/* Permission is hereby granted, free of charge, to any person obtaining */
12+
/* a copy of this software and associated documentation files (the */
13+
/* "Software"), to deal in the Software without restriction, including */
14+
/* without limitation the rights to use, copy, modify, merge, publish, */
15+
/* distribute, sublicense, and/or sell copies of the Software, and to */
16+
/* permit persons to whom the Software is furnished to do so, subject to */
17+
/* the following conditions: */
18+
/* */
19+
/* The above copyright notice and this permission notice shall be */
20+
/* included in all copies or substantial portions of the Software. */
21+
/* */
22+
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23+
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24+
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25+
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26+
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27+
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28+
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29+
/**************************************************************************/
30+
31+
#pragma once
32+
33+
#include "core/string/string_name.h"
34+
#include "core/templates/vector.h"
35+
36+
class GDType {
37+
const GDType *super_type;
38+
39+
StringName name;
40+
/// Contains all the class names in order:
41+
/// `name` is the first element and `Object` is the last.
42+
Vector<StringName> name_hierarchy;
43+
44+
public:
45+
GDType(const GDType *p_super_type, StringName p_name);
46+
47+
const GDType *get_super_type() const { return super_type; }
48+
const StringName &get_name() const { return name; }
49+
const Vector<StringName> &get_name_hierarchy() const { return name_hierarchy; }
50+
};

core/object/object.cpp

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ bool Object::_predelete() {
258258
return false;
259259
}
260260

261-
_class_name_ptr = nullptr; // Must restore, so constructors/destructors have proper class name access at each stage.
261+
_gdtype_ptr = nullptr; // Must restore, so constructors/destructors have proper class name access at each stage.
262262
notification(NOTIFICATION_PREDELETE_CLEANUP, true);
263263

264264
// Destruction order starts with the most derived class, and progresses towards the base Object class:
@@ -301,7 +301,7 @@ void Object::cancel_free() {
301301

302302
void Object::_initialize() {
303303
// Cache the class name in the object for quick reference.
304-
_class_name_ptr = _get_class_namev();
304+
_gdtype_ptr = &_get_typev();
305305
_initialize_classv();
306306
}
307307

@@ -2085,18 +2085,34 @@ uint32_t Object::get_edited_version() const {
20852085
}
20862086
#endif
20872087

2088+
const GDType &Object::get_gdtype() const {
2089+
if (unlikely(!_gdtype_ptr)) {
2090+
// While class is initializing / deinitializing, constructors and destructors
2091+
// need access to the proper type at the proper stage.
2092+
return _get_typev();
2093+
}
2094+
return *_gdtype_ptr;
2095+
}
2096+
2097+
bool Object::is_class(const String &p_class) const {
2098+
if (_extension && _extension->is_class(p_class)) {
2099+
return true;
2100+
}
2101+
for (const StringName &name : get_gdtype().get_name_hierarchy()) {
2102+
if (name == p_class) {
2103+
return true;
2104+
}
2105+
}
2106+
return false;
2107+
}
2108+
20882109
const StringName &Object::get_class_name() const {
20892110
if (_extension) {
20902111
// Can't put inside the unlikely as constructor can run it.
20912112
return _extension->class_name;
20922113
}
20932114

2094-
if (unlikely(!_class_name_ptr)) {
2095-
// While class is initializing / deinitializing, constructors and destructors
2096-
// need access to the proper class at the proper stage.
2097-
return *_get_class_namev();
2098-
}
2099-
return *_class_name_ptr;
2115+
return get_gdtype().get_name();
21002116
}
21012117

21022118
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
21052121
// have to return the closest native parent's class name, so that it doesn't try to
21062122
// use this like the real object.
21072123
if (unlikely(_extension && _extension->library == p_library && _extension->is_placeholder)) {
2108-
const StringName *class_name = _get_class_namev();
2109-
return *class_name;
2124+
return get_class_name();
21102125
}
21112126
#endif
21122127

@@ -2116,13 +2131,13 @@ StringName Object::get_class_name_for_extension(const GDExtension *p_library) co
21162131
}
21172132

21182133
// Extensions only have wrapper classes for classes exposed in ClassDB.
2119-
const StringName *class_name = _get_class_namev();
2120-
if (ClassDB::is_class_exposed(*class_name)) {
2121-
return *class_name;
2134+
const StringName &class_name = get_class_name();
2135+
if (ClassDB::is_class_exposed(class_name)) {
2136+
return class_name;
21222137
}
21232138

21242139
// Find the nearest parent class that's exposed.
2125-
StringName parent_class = ClassDB::get_parent_class(*class_name);
2140+
StringName parent_class = ClassDB::get_parent_class(class_name);
21262141
while (parent_class != StringName()) {
21272142
if (ClassDB::is_class_exposed(parent_class)) {
21282143
return parent_class;
@@ -2296,14 +2311,16 @@ void Object::detach_from_objectdb() {
22962311
}
22972312
}
22982313

2299-
void Object::assign_class_name_static(const Span<char> &p_name, StringName &r_target) {
2314+
void Object::assign_type_static(GDType **type_ptr, const char *p_name, const GDType *super_type) {
23002315
static BinaryMutex _mutex;
23012316
MutexLock lock(_mutex);
2302-
if (r_target) {
2303-
// Already assigned while we were waiting for the mutex.
2317+
GDType *type = *type_ptr;
2318+
if (type) {
2319+
// Assigned while we were waiting.
23042320
return;
23052321
}
2306-
r_target = StringName(p_name.ptr(), true);
2322+
type = memnew(GDType(super_type, StringName(p_name, true)));
2323+
*type_ptr = type;
23072324
}
23082325

23092326
Object::~Object() {

core/object/object.h

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#pragma once
3232

3333
#include "core/extension/gdextension_interface.h"
34+
#include "core/object/gdtype.h"
3435
#include "core/object/message_queue.h"
3536
#include "core/object/object_id.h"
3637
#include "core/os/spin_lock.h"
@@ -495,21 +496,18 @@ private:
495496
friend class ::ClassDB; \
496497
\
497498
public: \
498-
virtual const StringName *_get_class_namev() const override { \
499-
return &get_class_static(); \
499+
virtual const GDType &_get_typev() const override { \
500+
return get_gdtype_static(); \
500501
} \
501-
static const StringName &get_class_static() { \
502-
static StringName _class_name_static; \
503-
if (unlikely(!_class_name_static)) { \
504-
assign_class_name_static(#m_class, _class_name_static); \
502+
static const GDType &get_gdtype_static() { \
503+
static GDType *_class_static; \
504+
if (unlikely(!_class_static)) { \
505+
assign_type_static(&_class_static, #m_class, &super_type::get_gdtype_static()); \
505506
} \
506-
return _class_name_static; \
507+
return *_class_static; \
507508
} \
508-
virtual bool is_class(const String &p_class) const override { \
509-
if (_get_extension() && _get_extension()->is_class(p_class)) { \
510-
return true; \
511-
} \
512-
return (p_class == (#m_class)) ? true : m_inherits::is_class(p_class); \
509+
static const StringName &get_class_static() { \
510+
return get_gdtype_static().get_name(); \
513511
} \
514512
\
515513
protected: \
@@ -669,7 +667,7 @@ class Object {
669667
Variant script; // Reference does not exist yet, store it in a Variant.
670668
HashMap<StringName, Variant> metadata;
671669
HashMap<StringName, Variant *> metadata_properties;
672-
mutable const StringName *_class_name_ptr = nullptr;
670+
mutable const GDType *_gdtype_ptr = nullptr;
673671

674672
void _add_user_signal(const String &p_name, const Array &p_args = Array());
675673
bool _has_user_signal(const StringName &p_name) const;
@@ -775,9 +773,7 @@ class Object {
775773
Variant _call_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
776774
Variant _call_deferred_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
777775

778-
virtual const StringName *_get_class_namev() const {
779-
return &get_class_static();
780-
}
776+
virtual const GDType &_get_typev() const { return get_gdtype_static(); }
781777

782778
TypedArray<StringName> _get_meta_list_bind() const;
783779
TypedArray<Dictionary> _get_property_list_bind() const;
@@ -843,26 +839,25 @@ class Object {
843839
};
844840

845841
/* TYPE API */
846-
static void assign_class_name_static(const Span<char> &p_name, StringName &r_target);
842+
static void assign_type_static(GDType **type_ptr, const char *p_name, const GDType *super_type);
847843

848-
static const StringName &get_class_static() {
849-
static StringName _class_name_static;
850-
if (unlikely(!_class_name_static)) {
851-
assign_class_name_static("Object", _class_name_static);
844+
static const GDType &get_gdtype_static() {
845+
static GDType *_class_static;
846+
if (unlikely(!_class_static)) {
847+
assign_type_static(&_class_static, "Object", nullptr);
852848
}
853-
return _class_name_static;
849+
return *_class_static;
854850
}
855851

852+
const GDType &get_gdtype() const;
853+
854+
static const StringName &get_class_static() { return get_gdtype_static().get_name(); }
855+
856856
_FORCE_INLINE_ String get_class() const { return get_class_name(); }
857857

858858
virtual String get_save_class() const { return get_class(); } //class stored when saving
859859

860-
virtual bool is_class(const String &p_class) const {
861-
if (_extension && _extension->is_class(p_class)) {
862-
return true;
863-
}
864-
return (p_class == "Object");
865-
}
860+
bool is_class(const String &p_class) const;
866861
virtual bool is_class_ptr(void *p_ptr) const { return get_class_ptr_static() == p_ptr; }
867862

868863
template <typename T>

0 commit comments

Comments
 (0)