From b295f0c7a9273079d9fbfc32ad30414c029897cd Mon Sep 17 00:00:00 2001 From: nlupugla Date: Sat, 27 Apr 2024 15:50:10 -0400 Subject: [PATCH] Rebased and cleaned up memory in struct unit tests. --- core/core_bind.cpp | 18 ++++---- core/object/object.compat.inc | 0 core/object/property_info.h | 11 ++--- core/variant/array.cpp | 12 ++++-- core/variant/dictionary.cpp | 72 ++++++++++++++++---------------- core/variant/struct.cpp | 42 ------------------- core/variant/struct_generator.h | 33 +++++++++++---- tests/core/variant/test_struct.h | 7 ++-- 8 files changed, 89 insertions(+), 106 deletions(-) create mode 100644 core/object/object.compat.inc delete mode 100644 core/variant/struct.cpp diff --git a/core/core_bind.cpp b/core/core_bind.cpp index c3c8184342b6..9b2e6a78486a 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -1627,10 +1627,6 @@ bool ClassDB::is_class_enum_bitfield(const StringName &p_class, const StringName return ::ClassDB::is_enum_bitfield(p_class, p_enum, p_no_inheritance); } -bool ClassDB::is_class_enabled(const StringName &p_class) const { - return ::ClassDB::is_class_enabled(p_class); -} - bool ClassDB::class_has_struct(const StringName &p_class, const StringName &p_struct, bool p_no_inheritance) const { return ::ClassDB::get_struct_info(p_class, p_struct, p_no_inheritance) != nullptr; } @@ -1672,6 +1668,10 @@ TypedArray ClassDB::class_get_struct_members(const StringName &p_cla return ret; } +bool ClassDB::is_class_enabled(const StringName &p_class) const { + return ::ClassDB::is_class_enabled(p_class); +} + #ifdef TOOLS_ENABLED void ClassDB::get_argument_options(const StringName &p_function, int p_idx, List *r_options) const { const String pf = p_function; @@ -1679,9 +1679,9 @@ void ClassDB::get_argument_options(const StringName &p_function, int p_idx, List if (p_idx == 0) { first_argument_is_class = (pf == "get_inheriters_from_class" || pf == "get_parent_class" || pf == "class_exists" || pf == "can_instantiate" || pf == "instantiate" || - pf == "class_has_signal" || pf == "class_get_signal" || pf == "class_get_signal_list" || - pf == "class_get_property_list" || pf == "class_get_property" || pf == "class_set_property" || - pf == "class_has_method" || pf == "class_get_method_list" || + pf == "class_has_signal" || pf == "class_get_signal" || pf == "class_get_signal_list" || pf == "class_get_signal_list_as_struct" || + pf == "class_get_property_list" || pf == "class_get_property_list_as_structs" || pf == "class_get_property" || pf == "class_set_property" || + pf == "class_has_method" || pf == "class_get_method_list" || pf == "class_get_method_list_as_structs" || pf == "class_get_integer_constant_list" || pf == "class_has_integer_constant" || pf == "class_get_integer_constant" || pf == "class_has_enum" || pf == "class_get_enum_list" || pf == "class_get_enum_constants" || pf == "class_get_integer_constant_enum" || pf == "is_class_enabled" || pf == "is_class_enum_bitfield"); @@ -1741,11 +1741,11 @@ void ClassDB::_bind_methods() { ::ClassDB::bind_method(D_METHOD("is_class_enum_bitfield", "class", "enum", "no_inheritance"), &ClassDB::is_class_enum_bitfield, DEFVAL(false)); - ::ClassDB::bind_method(D_METHOD("is_class_enabled", "class"), &ClassDB::is_class_enabled); - ::ClassDB::bind_method(D_METHOD("class_has_struct", "class", "struct", "no_inheritance"), &ClassDB::class_has_struct, DEFVAL(false)); ::ClassDB::bind_method(D_METHOD("class_get_struct_list", "class", "no_inheritance"), &ClassDB::class_get_struct_list, DEFVAL(false)); ::ClassDB::bind_method(D_METHOD("class_get_struct_members", "class", "struct"), &ClassDB::class_get_struct_members); + + ::ClassDB::bind_method(D_METHOD("is_class_enabled", "class"), &ClassDB::is_class_enabled); } } // namespace special diff --git a/core/object/object.compat.inc b/core/object/object.compat.inc new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/core/object/property_info.h b/core/object/property_info.h index 18f1bef22057..8cff7af69402 100644 --- a/core/object/property_info.h +++ b/core/object/property_info.h @@ -37,7 +37,7 @@ enum PropertyHint { PROPERTY_HINT_NONE, ///< no hint provided. - PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_less][,hide_slider][,radians][,degrees][,exp][,suffix:] range. + PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_less][,hide_slider][,radians_as_degrees][,degrees][,exp][,suffix:] range. PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc" PROPERTY_HINT_ENUM_SUGGESTION, ///< hint_text= "val1,val2,val3,etc" PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) use "attenuation" hint string to revert (flip h), "positive_only" to exclude in-out and out-in. (ie: "attenuation,positive_only") @@ -60,12 +60,12 @@ enum PropertyHint { PROPERTY_HINT_COLOR_NO_ALPHA, ///< used for ignoring alpha component when editing a color PROPERTY_HINT_OBJECT_ID, PROPERTY_HINT_TYPE_STRING, ///< a type string, the hint is the base type to choose - PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE, ///< so something else can provide this (used in scripts) + PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE, // Deprecated. 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_GLOBAL_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_INT_IS_OBJECTID, // Deprecated. PROPERTY_HINT_INT_IS_POINTER, PROPERTY_HINT_ARRAY_TYPE, PROPERTY_HINT_LOCALE_ID, @@ -74,6 +74,7 @@ enum PropertyHint { PROPERTY_HINT_HIDE_QUATERNION_EDIT, /// Only Node3D::transform should hide the quaternion editor. PROPERTY_HINT_PASSWORD, PROPERTY_HINT_LAYERS_AVOIDANCE, + PROPERTY_HINT_DICTIONARY_TYPE, PROPERTY_HINT_MAX, }; @@ -93,7 +94,7 @@ enum PropertyUsageFlags { PROPERTY_USAGE_SCRIPT_VARIABLE = 1 << 12, PROPERTY_USAGE_STORE_IF_NULL = 1 << 13, PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED = 1 << 14, - PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE = 1 << 15, + PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE = 1 << 15, // Deprecated. PROPERTY_USAGE_CLASS_IS_ENUM = 1 << 16, PROPERTY_USAGE_NIL_IS_VARIANT = 1 << 17, PROPERTY_USAGE_ARRAY = 1 << 18, // Used in the inspector to group properties as elements of an array. @@ -103,7 +104,7 @@ enum PropertyUsageFlags { PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT = 1 << 22, PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT = 1 << 23, PROPERTY_USAGE_KEYING_INCREMENTS = 1 << 24, // Used in inspector to increment property when keyed in animation player. - PROPERTY_USAGE_DEFERRED_SET_RESOURCE = 1 << 25, // when loading, the resource for this property can be set at the end of loading. + PROPERTY_USAGE_DEFERRED_SET_RESOURCE = 1 << 25, // Deprecated. PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT = 1 << 26, // For Object properties, instantiate them when creating in editor. PROPERTY_USAGE_EDITOR_BASIC_SETTING = 1 << 27, //for project or editor settings, show when basic settings are selected. PROPERTY_USAGE_READ_ONLY = 1 << 28, // Mark a property as read-only in the inspector. diff --git a/core/variant/array.cpp b/core/variant/array.cpp index b622f32a83ef..c6de629f341b 100644 --- a/core/variant/array.cpp +++ b/core/variant/array.cpp @@ -564,7 +564,14 @@ Array Array::duplicate(bool p_deep) const { Array Array::recursive_duplicate(bool p_deep, int recursion_count) const { Array new_arr; - new_arr._p->typed = _p->typed; + if (const StructInfo *struct_info = get_struct_info()) { + new_arr.set_struct(*struct_info, is_array_of_structs()); + } else { + new_arr._p->typed = _p->typed; + if (p_deep) { + new_arr.resize(size()); + } + } if (recursion_count > MAX_RECURSION) { ERR_PRINT("Max recursion reached"); @@ -574,7 +581,6 @@ Array Array::recursive_duplicate(bool p_deep, int recursion_count) const { if (p_deep) { recursion_count++; int element_count = size(); - new_arr.resize(element_count); for (int i = 0; i < element_count; i++) { new_arr[i] = get(i).recursive_duplicate(true, recursion_count); } @@ -1040,7 +1046,7 @@ Array::Array(const StructInfo &p_struct_info, bool is_array_of_structs) { if (!is_array_of_structs) { Variant *pw = _p->array.ptrw(); for (int32_t i = 0; i < p_struct_info.count; i++) { - pw[i] = p_struct_info.default_values[i]; + pw[i] = p_struct_info.default_values[i].duplicate(true); } } } diff --git a/core/variant/dictionary.cpp b/core/variant/dictionary.cpp index 92615b5cbced..bfd8ecd14c49 100644 --- a/core/variant/dictionary.cpp +++ b/core/variant/dictionary.cpp @@ -153,9 +153,9 @@ Variant *Dictionary::getptr(const Variant &p_key) { } Variant Dictionary::get_valid(const Variant &p_key) const { - Variant key = p_key; - ERR_FAIL_COND_V(!_p->typed_key.validate(key, "get_valid"), Variant()); - HashMap::ConstIterator E(_p->variant_map.find(key)); + ValidatedVariant validated = _p->typed_key.validate(p_key, "get_valid"); + ERR_FAIL_COND_V(!validated.valid, Variant()); + HashMap::ConstIterator E(_p->variant_map.find(validated.value)); if (!E) { return Variant(); @@ -164,9 +164,9 @@ Variant Dictionary::get_valid(const Variant &p_key) const { } Variant Dictionary::get(const Variant &p_key, const Variant &p_default) const { - Variant key = p_key; - ERR_FAIL_COND_V(!_p->typed_key.validate(key, "get"), p_default); - const Variant *result = getptr(key); + ValidatedVariant validated = _p->typed_key.validate(p_key, "get"); + ERR_FAIL_COND_V(!validated.valid, p_default); + const Variant *result = getptr(validated.value); if (!result) { return p_default; } @@ -175,16 +175,18 @@ Variant Dictionary::get(const Variant &p_key, const Variant &p_default) const { } Variant Dictionary::get_or_add(const Variant &p_key, const Variant &p_default) { - Variant key = p_key; - ERR_FAIL_COND_V(!_p->typed_key.validate(key, "get"), p_default); - const Variant *result = getptr(key); - if (!result) { - Variant value = p_default; - ERR_FAIL_COND_V(!_p->typed_value.validate(value, "add"), value); - operator[](key) = value; - return value; + ValidatedVariant validated_key = _p->typed_key.validate(p_key, "get"); + ERR_FAIL_COND_V(!validated_key.valid, p_default); + const Variant *result = getptr(validated_key.value); + + if (result) { + return *result; } - return *result; + + ValidatedVariant validated_default = _p->typed_key.validate(p_default, "add"); + ERR_FAIL_COND_V(!validated_default.valid, validated_default.value); + operator[](validated_key.value) = validated_default.value; + return validated_default.value; } bool Dictionary::set(const Variant &p_key, const Variant &p_value) { @@ -206,16 +208,16 @@ bool Dictionary::is_empty() const { } bool Dictionary::has(const Variant &p_key) const { - Variant key = p_key; - ERR_FAIL_COND_V(!_p->typed_key.validate(key, "use 'has'"), false); + ValidatedVariant validated = _p->typed_key.validate(p_key, "use 'has'"); + ERR_FAIL_COND_V(!validated.valid, false); return _p->variant_map.has(p_key); } bool Dictionary::has_all(const Array &p_keys) const { for (int i = 0; i < p_keys.size(); i++) { - Variant key = p_keys[i]; - ERR_FAIL_COND_V(!_p->typed_key.validate(key, "use 'has_all'"), false); - if (!has(key)) { + ValidatedVariant validated = _p->typed_key.validate(p_keys[i], "use 'has_all'"); + ERR_FAIL_COND_V(!validated.valid, false); + if (!has(validated.value)) { return false; } } @@ -223,10 +225,10 @@ bool Dictionary::has_all(const Array &p_keys) const { } Variant Dictionary::find_key(const Variant &p_value) const { - Variant value = p_value; - ERR_FAIL_COND_V(!_p->typed_value.validate(value, "find_key"), Variant()); + ValidatedVariant validated = _p->typed_key.validate(p_value, "find_key"); + ERR_FAIL_COND_V(!validated.valid, Variant()); for (const KeyValue &E : _p->variant_map) { - if (E.value == value) { + if (E.value == validated.value) { return E.key; } } @@ -234,10 +236,10 @@ Variant Dictionary::find_key(const Variant &p_value) const { } bool Dictionary::erase(const Variant &p_key) { - Variant key = p_key; - ERR_FAIL_COND_V(!_p->typed_key.validate(key, "erase"), false); + ValidatedVariant validated = _p->typed_key.validate(p_key, "erase"); + ERR_FAIL_COND_V(!validated.valid, false); ERR_FAIL_COND_V_MSG(_p->read_only, false, "Dictionary is in read-only state."); - return _p->variant_map.erase(key); + return _p->variant_map.erase(validated.value); } bool Dictionary::operator==(const Dictionary &p_dictionary) const { @@ -297,12 +299,12 @@ void Dictionary::clear() { void Dictionary::merge(const Dictionary &p_dictionary, bool p_overwrite) { ERR_FAIL_COND_MSG(_p->read_only, "Dictionary is in read-only state."); for (const KeyValue &E : p_dictionary._p->variant_map) { - Variant key = E.key; - Variant value = E.value; - ERR_FAIL_COND(!_p->typed_key.validate(key, "merge")); - ERR_FAIL_COND(!_p->typed_value.validate(value, "merge")); - if (p_overwrite || !has(key)) { - operator[](key) = value; + ValidatedVariant validated_key = _p->typed_key.validate(E.key, "merge"); + ERR_FAIL_COND(!validated_key.valid); + ValidatedVariant validated_value = _p->typed_key.validate(E.value, "merge"); + ERR_FAIL_COND(!validated_value.valid); + if (p_overwrite || !has(validated_key.value)) { + operator[](validated_key.value) = validated_value.value; } } } @@ -536,9 +538,9 @@ const Variant *Dictionary::next(const Variant *p_key) const { } return nullptr; } - Variant key = *p_key; - ERR_FAIL_COND_V(!_p->typed_key.validate(key, "next"), nullptr); - HashMap::Iterator E = _p->variant_map.find(key); + ValidatedVariant validated = _p->typed_key.validate(*p_key, "next"); + ERR_FAIL_COND_V(!validated.valid, nullptr); + HashMap::Iterator E = _p->variant_map.find(validated.value); if (!E) { return nullptr; diff --git a/core/variant/struct.cpp b/core/variant/struct.cpp deleted file mode 100644 index 3d31efee3ae9..000000000000 --- a/core/variant/struct.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/**************************************************************************/ -/* struct.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 "core/variant/struct.h" -//#include "core/object/object.h" - -//template -//PropertyInfo GetTypeInfo>::get_class_info() { -// return PropertyInfo(Variant::ARRAY, String(), PROPERTY_HINT_ARRAY_TYPE, T::Layout::get_struct_name()); -//} - -//template -//PropertyInfo GetTypeInfo &>::get_class_info() { -// return PropertyInfo(Variant::ARRAY, String(), PROPERTY_HINT_ARRAY_TYPE, T::Layout::get_struct_name()); -//} \ No newline at end of file diff --git a/core/variant/struct_generator.h b/core/variant/struct_generator.h index 9da8d272da84..082fa1fd6495 100644 --- a/core/variant/struct_generator.h +++ b/core/variant/struct_generator.h @@ -182,18 +182,33 @@ struct StructInfo { Vector default_values; StructInfo(){}; - StructInfo(const StringName &p_name, const int32_t p_count, const Vector &p_names, const Vector &p_types, const Vector &p_class_names, const Vector &p_struct_member_infos, const Vector &p_default_values) { - name = p_name; - count = p_count; - names = p_names; - types = p_types; - class_names = p_class_names; - struct_member_infos = p_struct_member_infos; - default_values = p_default_values; - }; + StructInfo(const StringName &p_name, const int32_t p_count) : + name(p_name), count(p_count) { + names.resize(p_count); + types.resize(p_count); + class_names.resize(p_count); + struct_member_infos.resize(p_count); + default_values.resize(p_count); + } + StructInfo(const StringName &p_name, const int32_t p_count, const Vector &p_names, const Vector &p_types, const Vector &p_class_names, const Vector &p_struct_member_infos, const Vector &p_default_values) : + name(p_name), + count(p_count), + names(p_names), + types(p_types), + class_names(p_class_names), + struct_member_infos(p_struct_member_infos), + default_values(p_default_values){}; Dictionary to_dict() const; + _FORCE_INLINE_ void set(int32_t p_index, const StringName &p_name, const Variant::Type &p_type, const StringName &p_class_name, const StructInfo *p_struct_member_info, const Variant &p_default_value) { + names.write[p_index] = p_name; + types.write[p_index] = p_type; + class_names.write[p_index] = p_class_name; + struct_member_infos.write[p_index] = p_struct_member_info; + default_values.write[p_index] = p_default_value; + } + _FORCE_INLINE_ bool operator==(const StructInfo &p_struct_info) const { return name == p_struct_info.name; } diff --git a/tests/core/variant/test_struct.h b/tests/core/variant/test_struct.h index 61e9d2817c07..3a0044683e1d 100644 --- a/tests/core/variant/test_struct.h +++ b/tests/core/variant/test_struct.h @@ -188,7 +188,7 @@ TEST_CASE("[Struct] PropertyInfo") { List list; my_node->get_property_list(&list); - PropertyInfo info = list[0]; + PropertyInfo info = list.get(0); TypedArray> property_list = my_node->call(SNAME("get_property_list_as_structs")); Struct prop = property_list[0]; @@ -226,6 +226,7 @@ TEST_CASE("[Struct] PropertyInfo") { variant_prop.set_named(SNAME("oops"), SNAME("oh no"), valid); CHECK_EQ(valid, false); } + memdelete(my_node); } TEST_CASE("[Struct] Validation") { @@ -282,8 +283,6 @@ TEST_CASE("[Struct] Validation") { ERR_PRINT_ON; named_int.assign(also_a_match); - bool matches = named_int == also_a_match; - print_line(matches); CHECK_MESSAGE(named_int == also_a_match, "failed to assign an array with correct types using 'assign' function"); } } @@ -346,6 +345,8 @@ TEST_CASE("[Struct] Nesting") { nested_struct.set_named("value", basic_struct_lookalike); CHECK_EQ(nested_struct["value"], basic_struct); ERR_PRINT_ON; + + memdelete(node); } SUBCASE("Typed Array of Struct") {