From 361e3b4fe80507da5a48778abb8cf8895d644021 Mon Sep 17 00:00:00 2001 From: Thaddeus Crews Date: Wed, 21 Aug 2024 13:32:25 -0500 Subject: [PATCH] Core: Expand `std::initializer_list` support --- core/templates/a_hash_map.h | 7 +++++++ core/templates/cowdata.h | 15 ++++++++++++++ core/templates/hash_map.h | 9 +++++++++ core/templates/hash_set.h | 7 +++++++ core/templates/list.h | 8 ++++++++ core/templates/oa_hash_map.h | 8 ++++++++ core/templates/rb_map.h | 8 ++++++++ core/templates/rb_set.h | 8 ++++++++ core/templates/safe_list.h | 8 ++++++++ core/templates/vector.h | 11 ++--------- core/templates/vmap.h | 2 ++ core/templates/vset.h | 4 ++++ tests/core/templates/test_a_hash_map.h | 18 +++++++++++++++++ tests/core/templates/test_hash_map.h | 18 +++++++++++++++++ tests/core/templates/test_hash_set.h | 18 +++++++++++++++++ tests/core/templates/test_list.h | 11 +++++++++++ tests/core/templates/test_oa_hash_map.h | 26 +++++++++++++++++++++++++ 17 files changed, 177 insertions(+), 9 deletions(-) diff --git a/core/templates/a_hash_map.h b/core/templates/a_hash_map.h index 6e3a978d50..de24fe4487 100644 --- a/core/templates/a_hash_map.h +++ b/core/templates/a_hash_map.h @@ -703,6 +703,13 @@ public: capacity(INITIAL_CAPACITY - 1) { } + AHashMap(std::initializer_list> p_init) { + reserve(p_init.size()); + for (const KeyValue &E : p_init) { + insert(E.key, E.value); + } + } + void reset() { if (elements != nullptr) { if constexpr (!(std::is_trivially_destructible_v && std::is_trivially_destructible_v)) { diff --git a/core/templates/cowdata.h b/core/templates/cowdata.h index f87fa1ad81..b45a726d3c 100644 --- a/core/templates/cowdata.h +++ b/core/templates/cowdata.h @@ -36,6 +36,7 @@ #include "core/templates/safe_refcount.h" #include +#include #include template @@ -250,6 +251,7 @@ public: _FORCE_INLINE_ CowData() {} _FORCE_INLINE_ ~CowData(); + _FORCE_INLINE_ CowData(std::initializer_list p_init); _FORCE_INLINE_ CowData(const CowData &p_from) { _ref(p_from); } _FORCE_INLINE_ CowData(CowData &&p_from) { _ptr = p_from._ptr; @@ -492,6 +494,19 @@ CowData::~CowData() { _unref(); } +template +CowData::CowData(std::initializer_list p_init) { + Error err = resize(p_init.size()); + if (err != OK) { + return; + } + + Size i = 0; + for (const T &element : p_init) { + set(i++, element); + } +} + #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic pop #endif diff --git a/core/templates/hash_map.h b/core/templates/hash_map.h index 329952e8d4..e3fe1fa9f0 100644 --- a/core/templates/hash_map.h +++ b/core/templates/hash_map.h @@ -37,6 +37,8 @@ #include "core/templates/paged_allocator.h" #include "core/templates/pair.h" +#include + /** * A HashMap implementation that uses open addressing with Robin Hood hashing. * Robin Hood hashing swaps out entries that have a smaller probing distance @@ -640,6 +642,13 @@ public: capacity_index = MIN_CAPACITY_INDEX; } + HashMap(std::initializer_list> p_init) { + reserve(p_init.size()); + for (const KeyValue &E : p_init) { + insert(E.key, E.value); + } + } + uint32_t debug_get_hash(uint32_t p_index) { if (num_elements == 0) { return 0; diff --git a/core/templates/hash_set.h b/core/templates/hash_set.h index 295b07e5e7..9a08da1dc3 100644 --- a/core/templates/hash_set.h +++ b/core/templates/hash_set.h @@ -445,6 +445,13 @@ public: capacity_index = MIN_CAPACITY_INDEX; } + HashSet(std::initializer_list p_init) { + reserve(p_init.size()); + for (const TKey &E : p_init) { + insert(E); + } + } + void reset() { clear(); diff --git a/core/templates/list.h b/core/templates/list.h index 02afeec74d..055b6ade47 100644 --- a/core/templates/list.h +++ b/core/templates/list.h @@ -35,6 +35,8 @@ #include "core/os/memory.h" #include "core/templates/sort_array.h" +#include + /** * Generic Templatized Linked List Implementation. * The implementation differs from the STL one because @@ -763,6 +765,12 @@ public: List() {} + List(std::initializer_list p_init) { + for (const T &E : p_init) { + push_back(E); + } + } + ~List() { clear(); if (_data) { diff --git a/core/templates/oa_hash_map.h b/core/templates/oa_hash_map.h index 7afb58b7c2..edb3489576 100644 --- a/core/templates/oa_hash_map.h +++ b/core/templates/oa_hash_map.h @@ -34,6 +34,7 @@ #include "core/math/math_funcs.h" #include "core/os/memory.h" #include "core/templates/hashfuncs.h" +#include "core/templates/pair.h" /** * A HashMap implementation that uses open addressing with Robin Hood hashing. @@ -353,6 +354,13 @@ public: return it; } + OAHashMap(std::initializer_list> p_init) { + reserve(p_init.size()); + for (const KeyValue &E : p_init) { + set(E.key, E.value); + } + } + OAHashMap(const OAHashMap &p_other) { (*this) = p_other; } diff --git a/core/templates/rb_map.h b/core/templates/rb_map.h index ef555e4a16..09c8a1ca8d 100644 --- a/core/templates/rb_map.h +++ b/core/templates/rb_map.h @@ -35,6 +35,8 @@ #include "core/os/memory.h" #include "core/templates/pair.h" +#include + // based on the very nice implementation of rb-trees by: // https://web.archive.org/web/20120507164830/https://web.mit.edu/~emin/www/source_code/red_black_tree/index.html @@ -763,6 +765,12 @@ public: _copy_from(p_map); } + RBMap(std::initializer_list> p_init) { + for (const KeyValue &E : p_init) { + insert(E.key, E.value); + } + } + _FORCE_INLINE_ RBMap() {} ~RBMap() { diff --git a/core/templates/rb_set.h b/core/templates/rb_set.h index 1b69f2f0c2..cb2218d2c6 100644 --- a/core/templates/rb_set.h +++ b/core/templates/rb_set.h @@ -34,6 +34,8 @@ #include "core/os/memory.h" #include "core/typedefs.h" +#include + // based on the very nice implementation of rb-trees by: // https://web.archive.org/web/20120507164830/https://web.mit.edu/~emin/www/source_code/red_black_tree/index.html @@ -701,6 +703,12 @@ public: _copy_from(p_set); } + RBSet(std::initializer_list p_init) { + for (const T &E : p_init) { + insert(E); + } + } + _FORCE_INLINE_ RBSet() {} ~RBSet() { diff --git a/core/templates/safe_list.h b/core/templates/safe_list.h index 60ccdd9423..ab07077a5f 100644 --- a/core/templates/safe_list.h +++ b/core/templates/safe_list.h @@ -36,6 +36,7 @@ #include #include +#include #include // Design goals for these classes: @@ -226,6 +227,13 @@ public: return true; } + _FORCE_INLINE_ SafeList() {} + _FORCE_INLINE_ SafeList(std::initializer_list p_init) { + for (const T &E : p_init) { + insert(E); + } + } + ~SafeList() { #ifdef DEBUG_ENABLED if (!maybe_cleanup()) { diff --git a/core/templates/vector.h b/core/templates/vector.h index 3b60a35f0b..02f0783aef 100644 --- a/core/templates/vector.h +++ b/core/templates/vector.h @@ -283,15 +283,8 @@ public: } _FORCE_INLINE_ Vector() {} - _FORCE_INLINE_ Vector(std::initializer_list p_init) { - Error err = _cowdata.resize(p_init.size()); - ERR_FAIL_COND(err); - - Size i = 0; - for (const T &element : p_init) { - _cowdata.set(i++, element); - } - } + _FORCE_INLINE_ Vector(std::initializer_list p_init) : + _cowdata(p_init) {} _FORCE_INLINE_ Vector(const Vector &p_from) { _cowdata._ref(p_from._cowdata); } _FORCE_INLINE_ Vector(Vector &&p_from) : _cowdata(std::move(p_from._cowdata)) {} diff --git a/core/templates/vmap.h b/core/templates/vmap.h index 2ad074942b..c0cd35c2e0 100644 --- a/core/templates/vmap.h +++ b/core/templates/vmap.h @@ -194,6 +194,8 @@ public: } _FORCE_INLINE_ VMap() {} + _FORCE_INLINE_ VMap(std::initializer_list p_init) : + _cowdata(p_init) {} _FORCE_INLINE_ VMap(const VMap &p_from) { _cowdata._ref(p_from._cowdata); } inline void operator=(const VMap &p_from) { diff --git a/core/templates/vset.h b/core/templates/vset.h index 614d0e1e5f..d22f29bcc4 100644 --- a/core/templates/vset.h +++ b/core/templates/vset.h @@ -137,6 +137,10 @@ public: inline const T &operator[](int p_index) const { return _data[p_index]; } + + _FORCE_INLINE_ VSet() {} + _FORCE_INLINE_ VSet(std::initializer_list p_init) : + _data(p_init) {} }; #endif // VSET_H diff --git a/tests/core/templates/test_a_hash_map.h b/tests/core/templates/test_a_hash_map.h index e67ee7b441..4fa6d3bca4 100644 --- a/tests/core/templates/test_a_hash_map.h +++ b/tests/core/templates/test_a_hash_map.h @@ -37,6 +37,24 @@ namespace TestAHashMap { +TEST_CASE("[AHashMap] List initialization") { + AHashMap map{ { 0, "A" }, { 1, "B" }, { 2, "C" }, { 3, "D" }, { 4, "E" } }; + + CHECK(map.size() == 5); + CHECK(map[0] == "A"); + CHECK(map[1] == "B"); + CHECK(map[2] == "C"); + CHECK(map[3] == "D"); + CHECK(map[4] == "E"); +} + +TEST_CASE("[AHashMap] List initialization with existing elements") { + AHashMap map{ { 0, "A" }, { 0, "B" }, { 0, "C" }, { 0, "D" }, { 0, "E" } }; + + CHECK(map.size() == 1); + CHECK(map[0] == "E"); +} + TEST_CASE("[AHashMap] Insert element") { AHashMap map; AHashMap::Iterator e = map.insert(42, 84); diff --git a/tests/core/templates/test_hash_map.h b/tests/core/templates/test_hash_map.h index 6636afe9c6..2721a8cb69 100644 --- a/tests/core/templates/test_hash_map.h +++ b/tests/core/templates/test_hash_map.h @@ -37,6 +37,24 @@ namespace TestHashMap { +TEST_CASE("[HashMap] List initialization") { + HashMap map{ { 0, "A" }, { 1, "B" }, { 2, "C" }, { 3, "D" }, { 4, "E" } }; + + CHECK(map.size() == 5); + CHECK(map[0] == "A"); + CHECK(map[1] == "B"); + CHECK(map[2] == "C"); + CHECK(map[3] == "D"); + CHECK(map[4] == "E"); +} + +TEST_CASE("[HashMap] List initialization with existing elements") { + HashMap map{ { 0, "A" }, { 0, "B" }, { 0, "C" }, { 0, "D" }, { 0, "E" } }; + + CHECK(map.size() == 1); + CHECK(map[0] == "E"); +} + TEST_CASE("[HashMap] Insert element") { HashMap map; HashMap::Iterator e = map.insert(42, 84); diff --git a/tests/core/templates/test_hash_set.h b/tests/core/templates/test_hash_set.h index 7a618a1fe8..9eaa56df60 100644 --- a/tests/core/templates/test_hash_set.h +++ b/tests/core/templates/test_hash_set.h @@ -37,6 +37,24 @@ namespace TestHashSet { +TEST_CASE("[HashSet] List initialization") { + HashSet set{ 0, 1, 2, 3, 4 }; + + CHECK(set.size() == 5); + CHECK(set.has(0)); + CHECK(set.has(1)); + CHECK(set.has(2)); + CHECK(set.has(3)); + CHECK(set.has(4)); +} + +TEST_CASE("[HashSet] List initialization with existing elements") { + HashSet set{ 0, 0, 0, 0, 0 }; + + CHECK(set.size() == 1); + CHECK(set.has(0)); +} + TEST_CASE("[HashSet] Insert element") { HashSet set; HashSet::Iterator e = set.insert(42); diff --git a/tests/core/templates/test_list.h b/tests/core/templates/test_list.h index 6d95cca150..4e2ee93ad3 100644 --- a/tests/core/templates/test_list.h +++ b/tests/core/templates/test_list.h @@ -45,6 +45,17 @@ static void populate_integers(List &p_list, List::Element *r_elements[ } } +TEST_CASE("[List] List initialization") { + List list{ 0, 1, 2, 3, 4 }; + + CHECK(list.size() == 5); + CHECK(list.get(0) == 0); + CHECK(list.get(1) == 1); + CHECK(list.get(2) == 2); + CHECK(list.get(3) == 3); + CHECK(list.get(4) == 4); +} + TEST_CASE("[List] Push/pop back") { List list; diff --git a/tests/core/templates/test_oa_hash_map.h b/tests/core/templates/test_oa_hash_map.h index 9359efa964..5b9eab5836 100644 --- a/tests/core/templates/test_oa_hash_map.h +++ b/tests/core/templates/test_oa_hash_map.h @@ -38,6 +38,32 @@ namespace TestOAHashMap { +TEST_CASE("[OAHashMap] List initialization") { + OAHashMap map{ { 0, "A" }, { 1, "B" }, { 2, "C" }, { 3, "D" }, { 4, "E" } }; + + CHECK(map.get_num_elements() == 5); + String value; + CHECK(map.lookup(0, value)); + CHECK(value == "A"); + CHECK(map.lookup(1, value)); + CHECK(value == "B"); + CHECK(map.lookup(2, value)); + CHECK(value == "C"); + CHECK(map.lookup(3, value)); + CHECK(value == "D"); + CHECK(map.lookup(4, value)); + CHECK(value == "E"); +} + +TEST_CASE("[OAHashMap] List initialization with existing elements") { + OAHashMap map{ { 0, "A" }, { 0, "B" }, { 0, "C" }, { 0, "D" }, { 0, "E" } }; + + CHECK(map.get_num_elements() == 1); + String value; + CHECK(map.lookup(0, value)); + CHECK(value == "E"); +} + TEST_CASE("[OAHashMap] Insert element") { OAHashMap map; map.insert(42, 84);