From a5883dddf4eb4cf3953c16090ec3338dbc9e26fe Mon Sep 17 00:00:00 2001 From: Sam Date: Sat, 18 Mar 2023 13:45:20 +0000 Subject: [PATCH] add a set --- core/extension/extension_api_dump.cpp | 2 + core/variant/set.cpp | 296 ++++++++++++++++++++++++++ core/variant/set.h | 91 ++++++++ core/variant/variant.cpp | 4 + core/variant/variant.h | 2 + core/variant/variant_internal.h | 19 ++ 6 files changed, 414 insertions(+) create mode 100644 core/variant/set.cpp create mode 100644 core/variant/set.h diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp index e26ead6d8cb6..ad1dda522b36 100644 --- a/core/extension/extension_api_dump.cpp +++ b/core/extension/extension_api_dump.cpp @@ -169,6 +169,7 @@ Dictionary GDExtensionAPIDump::generate_extension_api() { { Variant::SIGNAL, sizeof(Signal), sizeof(Signal), sizeof(Signal), sizeof(Signal) }, // Hardcoded align. { Variant::DICTIONARY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, { Variant::ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::SET, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, { Variant::PACKED_BYTE_ARRAY, ptrsize_32 * 2, ptrsize_64 * 2, ptrsize_32 * 2, ptrsize_64 * 2 }, { Variant::PACKED_INT32_ARRAY, ptrsize_32 * 2, ptrsize_64 * 2, ptrsize_32 * 2, ptrsize_64 * 2 }, { Variant::PACKED_INT64_ARRAY, ptrsize_32 * 2, ptrsize_64 * 2, ptrsize_32 * 2, ptrsize_64 * 2 }, @@ -210,6 +211,7 @@ Dictionary GDExtensionAPIDump::generate_extension_api() { static_assert(type_size_array[Variant::SIGNAL][sizeof(void *)] == sizeof(Signal), "Size of Signal mismatch"); static_assert(type_size_array[Variant::DICTIONARY][sizeof(void *)] == sizeof(Dictionary), "Size of Dictionary mismatch"); static_assert(type_size_array[Variant::ARRAY][sizeof(void *)] == sizeof(Array), "Size of Array mismatch"); + static_assert(type_size_array[Variant::SET][sizeof(void *)] == sizeof(Set), "Size of Set mismatch"); static_assert(type_size_array[Variant::PACKED_BYTE_ARRAY][sizeof(void *)] == sizeof(PackedByteArray), "Size of PackedByteArray mismatch"); static_assert(type_size_array[Variant::PACKED_INT32_ARRAY][sizeof(void *)] == sizeof(PackedInt32Array), "Size of PackedInt32Array mismatch"); static_assert(type_size_array[Variant::PACKED_INT64_ARRAY][sizeof(void *)] == sizeof(PackedInt64Array), "Size of PackedInt64Array mismatch"); diff --git a/core/variant/set.cpp b/core/variant/set.cpp new file mode 100644 index 000000000000..175060b57fa4 --- /dev/null +++ b/core/variant/set.cpp @@ -0,0 +1,296 @@ +/**************************************************************************/ +/* dictionary.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 "set.h" + +#include "core/templates/hash_set.h" +#include "core/templates/safe_refcount.h" +#include "core/variant/variant.h" +// required in this order by VariantInternal, do not remove this comment. +#include "core/object/class_db.h" +#include "core/object/object.h" +#include "core/variant/type_info.h" +#include "core/variant/variant_internal.h" + +struct SetPrivate { + SafeRefCount refcount; + Variant *read_only = nullptr; // If enabled, a pointer is used to a temporary value that is used to return read-only values. + HashSet variant_map; +}; + +Variant Set::get_value_at_index(int p_index) const { + int index = 0; + for (const Variant &E : _p->variant_map) { + if (index == p_index) { + return E; + } + index++; + } + + return Variant(); +} + +const Variant *Set::getptr(const Variant &p_key) const { + auto E(_p->variant_map.find(p_key)); + if (!E) { + return nullptr; + } + return &(*E); +} + +Variant *Set::getptr(const Variant &p_key) { + auto E(_p->variant_map.find(p_key)); + if (!E) { + return nullptr; + } + if (unlikely(_p->read_only != nullptr)) { + *_p->read_only = *E; + return _p->read_only; + } else { + return const_cast(&(*E)); + } +} + +int Set::size() const { + return _p->variant_map.size(); +} + +bool Set::is_empty() const { + return !_p->variant_map.size(); +} + +bool Set::has(const Variant &p_key) const { + return _p->variant_map.has(p_key); +} + +bool Set::has_all(const Array &p_keys) const { + for (int i = 0; i < p_keys.size(); i++) { + if (!has(p_keys[i])) { + return false; + } + } + return true; +} + +bool Set::erase(const Variant &p_key) { + ERR_FAIL_COND_V_MSG(_p->read_only, false, "Dictionary is in read-only state."); + return _p->variant_map.erase(p_key); +} + +bool Set::operator==(const Set &p_dictionary) const { + return recursive_equal(p_dictionary, 0); +} + +bool Set::operator!=(const Set &p_dictionary) const { + return !recursive_equal(p_dictionary, 0); +} + +bool Set::recursive_equal(const Set &p_dictionary, int recursion_count) const { + // Cheap checks + if (_p == p_dictionary._p) { + return true; + } + if (_p->variant_map.size() != p_dictionary._p->variant_map.size()) { + return false; + } + + // Heavy O(n) check + if (recursion_count > MAX_RECURSION) { + ERR_PRINT("Max recursion reached"); + return true; + } + recursion_count++; + for (const Variant &this_E : _p->variant_map) { + HashSet::Iterator other_E(p_dictionary._p->variant_map.find(this_E)); + if (!other_E || !this_E.hash_compare(*other_E, recursion_count)) { + return false; + } + } + return true; +} + +void Set::_ref(const Set &p_from) const { + //make a copy first (thread safe) + if (!p_from._p->refcount.ref()) { + return; // couldn't copy + } + + //if this is the same, unreference the other one + if (p_from._p == _p) { + _p->refcount.unref(); + return; + } + if (_p) { + _unref(); + } + _p = p_from._p; +} + +void Set::clear() { + ERR_FAIL_COND_MSG(_p->read_only, "Dictionary is in read-only state."); + _p->variant_map.clear(); +} + +void Set::merge(const Set &p_dictionary, bool p_overwrite) { + +} + +void Set::_unref() const { + ERR_FAIL_COND(!_p); + if (_p->refcount.unref()) { + if (_p->read_only) { + memdelete(_p->read_only); + } + memdelete(_p); + } + _p = nullptr; +} + +uint32_t Set::hash() const { + return recursive_hash(0); +} + +uint32_t Set::recursive_hash(int recursion_count) const { + if (recursion_count > MAX_RECURSION) { + ERR_PRINT("Max recursion reached"); + return 0; + } + + uint32_t h = hash_murmur3_one_32(Variant::SET); + + recursion_count++; + for (const Variant &E : _p->variant_map) { + h = hash_murmur3_one_32(E.recursive_hash(recursion_count), h); + h = hash_murmur3_one_32(E.recursive_hash(recursion_count), h); + } + + return hash_fmix32(h); +} + +Array Set::values() const { + Array varr; + if (_p->variant_map.is_empty()) { + return varr; + } + + varr.resize(size()); + + int i = 0; + for (const Variant &E : _p->variant_map) { + varr[i] = E; + i++; + } + + return varr; +} + +const Variant *Set::next(const Variant *p_key) const { + if (p_key == nullptr) { + // caller wants to get the first element + if (_p->variant_map.begin()) { + return &(*_p->variant_map.begin()); + } + return nullptr; + } + HashSet::Iterator E = _p->variant_map.find(*p_key); + + if (!E) { + return nullptr; + } + + ++E; + + if (E) { + return &(*E); + } + + return nullptr; +} + +Set Set::duplicate(bool p_deep) const { + return recursive_duplicate(p_deep, 0); +} + +void Set::make_read_only() { + if (_p->read_only == nullptr) { + _p->read_only = memnew(Variant); + } +} +bool Set::is_read_only() const { + return _p->read_only != nullptr; +} + +Set Set::recursive_duplicate(bool p_deep, int recursion_count) const { + Set n; + + if (recursion_count > MAX_RECURSION) { + ERR_PRINT("Max recursion reached"); + return n; + } + +/* + if (p_deep) { + recursion_count++; + for (const KeyValue &E : _p->variant_map) { + n[E.key.recursive_duplicate(true, recursion_count)] = E.value.recursive_duplicate(true, recursion_count); + } + } else { + for (const KeyValue &E : _p->variant_map) { + n[E.key] = E.value; + } + } +*/ + return n; +} + +void Set::operator=(const Set &p_dictionary) { + if (this == &p_dictionary) { + return; + } + _ref(p_dictionary); +} + +const void *Set::id() const { + return _p; +} + +Set::Set(const Set &p_from) { + _p = nullptr; + _ref(p_from); +} + +Set::Set() { + _p = memnew(SetPrivate); + _p->refcount.init(); +} + +Set::~Set() { + _unref(); +} diff --git a/core/variant/set.h b/core/variant/set.h new file mode 100644 index 000000000000..a7681e5f72c8 --- /dev/null +++ b/core/variant/set.h @@ -0,0 +1,91 @@ +/**************************************************************************/ +/* dictionary.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. */ +/**************************************************************************/ + +#ifndef SET_H +#define SET_H + +#include "core/string/ustring.h" +#include "core/templates/list.h" +#include "core/variant/array.h" + +class Variant; + +struct SetPrivate; + +class Set { + mutable SetPrivate *_p; + + void _ref(const Set &p_from) const; + void _unref() const; + +public: + void get_key_list(List *p_keys) const; + Variant get_key_at_index(int p_index) const; + Variant get_value_at_index(int p_index) const; + + const Variant *getptr(const Variant &p_key) const; + Variant *getptr(const Variant &p_key); + + int size() const; + bool is_empty() const; + void clear(); + void merge(const Set &p_dictionary, bool p_overwrite = false); + + bool has(const Variant &p_key) const; + bool has_all(const Array &p_keys) const; + + bool erase(const Variant &p_key); + + bool operator==(const Set &p_dictionary) const; + bool operator!=(const Set &p_dictionary) const; + bool recursive_equal(const Set &p_dictionary, int recursion_count) const; + + uint32_t hash() const; + uint32_t recursive_hash(int recursion_count) const; + void operator=(const Set &p_dictionary); + + const Variant *next(const Variant *p_key = nullptr) const; + + Array values() const; + + Set duplicate(bool p_deep = false) const; + Set recursive_duplicate(bool p_deep, int recursion_count) const; + + void make_read_only(); + bool is_read_only() const; + + const void *id() const; + + Set(const Set &p_from); + Set(); + ~Set(); +}; + +#endif // SET_H diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp index 2da95598739a..8af2ffaca38c 100644 --- a/core/variant/variant.cpp +++ b/core/variant/variant.cpp @@ -138,6 +138,10 @@ String Variant::get_type_name(Variant::Type p_type) { case ARRAY: { return "Array"; } + case SET: { + return "Set"; + } + // Arrays. case PACKED_BYTE_ARRAY: { diff --git a/core/variant/variant.h b/core/variant/variant.h index f694e59051b9..4a585f5b7c06 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -59,6 +59,7 @@ #include "core/variant/array.h" #include "core/variant/callable.h" #include "core/variant/dictionary.h" +#include "core/variant/set.h" class Object; @@ -114,6 +115,7 @@ class Variant { SIGNAL, DICTIONARY, ARRAY, + SET, // typed arrays PACKED_BYTE_ARRAY, diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h index 0d55ee4ae2f4..5464826d4e30 100644 --- a/core/variant/variant_internal.h +++ b/core/variant/variant_internal.h @@ -84,6 +84,9 @@ class VariantInternal { case Variant::ARRAY: init_array(v); break; + case Variant::SET: + init_set(v); + break; case Variant::PACKED_BYTE_ARRAY: init_byte_array(v); break; @@ -182,6 +185,8 @@ class VariantInternal { _FORCE_INLINE_ static const Dictionary *get_dictionary(const Variant *v) { return reinterpret_cast(v->_data._mem); } _FORCE_INLINE_ static Array *get_array(Variant *v) { return reinterpret_cast(v->_data._mem); } _FORCE_INLINE_ static const Array *get_array(const Variant *v) { return reinterpret_cast(v->_data._mem); } + _FORCE_INLINE_ static Set *get_set(Variant *v) { return reinterpret_cast(v->_data._mem); } + _FORCE_INLINE_ static const Set *get_set(const Variant *v) { return reinterpret_cast(v->_data._mem); } // Typed arrays. _FORCE_INLINE_ static PackedByteArray *get_byte_array(Variant *v) { return &static_cast *>(v->_data.packed_array)->array; } @@ -274,6 +279,10 @@ class VariantInternal { memnew_placement(v->_data._mem, Array); v->type = Variant::ARRAY; } + _FORCE_INLINE_ static void init_set(Variant *v) { + memnew_placement(v->_data._mem, Set); + v->type = Variant::SET; + } _FORCE_INLINE_ static void init_byte_array(Variant *v) { v->_data.packed_array = Variant::PackedArrayRef::create(Vector()); v->type = Variant::PACKED_BYTE_ARRAY; @@ -395,6 +404,8 @@ class VariantInternal { return get_dictionary(v); case Variant::ARRAY: return get_array(v); + case Variant::SET: + return get_set(v); case Variant::PACKED_BYTE_ARRAY: return get_byte_array(v); case Variant::PACKED_INT32_ARRAY: @@ -479,6 +490,8 @@ class VariantInternal { return get_dictionary(v); case Variant::ARRAY: return get_array(v); + case Variant::SET: + return get_set(v); case Variant::PACKED_BYTE_ARRAY: return get_byte_array(v); case Variant::PACKED_INT32_ARRAY: @@ -739,6 +752,12 @@ struct VariantGetInternalPtr { static const Array *get_ptr(const Variant *v) { return VariantInternal::get_array(v); } }; +template <> +struct VariantGetInternalPtr { + static Set *get_ptr(Variant *v) { return VariantInternal::get_set(v); } + static const Set *get_ptr(const Variant *v) { return VariantInternal::get_set(v); } +}; + template <> struct VariantGetInternalPtr { static PackedByteArray *get_ptr(Variant *v) { return VariantInternal::get_byte_array(v); }