浏览代码

Merge pull request #95920 from Repiteo/core/initializer-list-templates

Core: Expand `std::initializer_list` support in container templates
Thaddeus Crews 8 月之前
父节点
当前提交
eaa447135c

+ 7 - 0
core/templates/a_hash_map.h

@@ -703,6 +703,13 @@ public:
 			capacity(INITIAL_CAPACITY - 1) {
 	}
 
+	AHashMap(std::initializer_list<KeyValue<TKey, TValue>> p_init) {
+		reserve(p_init.size());
+		for (const KeyValue<TKey, TValue> &E : p_init) {
+			insert(E.key, E.value);
+		}
+	}
+
 	void reset() {
 		if (elements != nullptr) {
 			if constexpr (!(std::is_trivially_destructible_v<TKey> && std::is_trivially_destructible_v<TValue>)) {

+ 15 - 0
core/templates/cowdata.h

@@ -36,6 +36,7 @@
 #include "core/templates/safe_refcount.h"
 
 #include <string.h>
+#include <initializer_list>
 #include <type_traits>
 
 template <typename T>
@@ -250,6 +251,7 @@ public:
 
 	_FORCE_INLINE_ CowData() {}
 	_FORCE_INLINE_ ~CowData();
+	_FORCE_INLINE_ CowData(std::initializer_list<T> p_init);
 	_FORCE_INLINE_ CowData(const CowData<T> &p_from) { _ref(p_from); }
 	_FORCE_INLINE_ CowData(CowData<T> &&p_from) {
 		_ptr = p_from._ptr;
@@ -492,6 +494,19 @@ CowData<T>::~CowData() {
 	_unref();
 }
 
+template <typename T>
+CowData<T>::CowData(std::initializer_list<T> 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

+ 9 - 0
core/templates/hash_map.h

@@ -37,6 +37,8 @@
 #include "core/templates/paged_allocator.h"
 #include "core/templates/pair.h"
 
+#include <initializer_list>
+
 /**
  * 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<KeyValue<TKey, TValue>> p_init) {
+		reserve(p_init.size());
+		for (const KeyValue<TKey, TValue> &E : p_init) {
+			insert(E.key, E.value);
+		}
+	}
+
 	uint32_t debug_get_hash(uint32_t p_index) {
 		if (num_elements == 0) {
 			return 0;

+ 7 - 0
core/templates/hash_set.h

@@ -445,6 +445,13 @@ public:
 		capacity_index = MIN_CAPACITY_INDEX;
 	}
 
+	HashSet(std::initializer_list<TKey> p_init) {
+		reserve(p_init.size());
+		for (const TKey &E : p_init) {
+			insert(E);
+		}
+	}
+
 	void reset() {
 		clear();
 

+ 8 - 0
core/templates/list.h

@@ -35,6 +35,8 @@
 #include "core/os/memory.h"
 #include "core/templates/sort_array.h"
 
+#include <initializer_list>
+
 /**
  * Generic Templatized Linked List Implementation.
  * The implementation differs from the STL one because
@@ -763,6 +765,12 @@ public:
 
 	List() {}
 
+	List(std::initializer_list<T> p_init) {
+		for (const T &E : p_init) {
+			push_back(E);
+		}
+	}
+
 	~List() {
 		clear();
 		if (_data) {

+ 8 - 0
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<KeyValue<TKey, TValue>> p_init) {
+		reserve(p_init.size());
+		for (const KeyValue<TKey, TValue> &E : p_init) {
+			set(E.key, E.value);
+		}
+	}
+
 	OAHashMap(const OAHashMap &p_other) {
 		(*this) = p_other;
 	}

+ 8 - 0
core/templates/rb_map.h

@@ -35,6 +35,8 @@
 #include "core/os/memory.h"
 #include "core/templates/pair.h"
 
+#include <initializer_list>
+
 // 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<KeyValue<K, V>> p_init) {
+		for (const KeyValue<K, V> &E : p_init) {
+			insert(E.key, E.value);
+		}
+	}
+
 	_FORCE_INLINE_ RBMap() {}
 
 	~RBMap() {

+ 8 - 0
core/templates/rb_set.h

@@ -34,6 +34,8 @@
 #include "core/os/memory.h"
 #include "core/typedefs.h"
 
+#include <initializer_list>
+
 // 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<T> p_init) {
+		for (const T &E : p_init) {
+			insert(E);
+		}
+	}
+
 	_FORCE_INLINE_ RBSet() {}
 
 	~RBSet() {

+ 8 - 0
core/templates/safe_list.h

@@ -36,6 +36,7 @@
 
 #include <atomic>
 #include <functional>
+#include <initializer_list>
 #include <type_traits>
 
 // Design goals for these classes:
@@ -226,6 +227,13 @@ public:
 		return true;
 	}
 
+	_FORCE_INLINE_ SafeList() {}
+	_FORCE_INLINE_ SafeList(std::initializer_list<T> p_init) {
+		for (const T &E : p_init) {
+			insert(E);
+		}
+	}
+
 	~SafeList() {
 #ifdef DEBUG_ENABLED
 		if (!maybe_cleanup()) {

+ 2 - 9
core/templates/vector.h

@@ -283,15 +283,8 @@ public:
 	}
 
 	_FORCE_INLINE_ Vector() {}
-	_FORCE_INLINE_ Vector(std::initializer_list<T> 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<T> 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)) {}

+ 2 - 0
core/templates/vmap.h

@@ -194,6 +194,8 @@ public:
 	}
 
 	_FORCE_INLINE_ VMap() {}
+	_FORCE_INLINE_ VMap(std::initializer_list<T> p_init) :
+			_cowdata(p_init) {}
 	_FORCE_INLINE_ VMap(const VMap &p_from) { _cowdata._ref(p_from._cowdata); }
 
 	inline void operator=(const VMap &p_from) {

+ 4 - 0
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<T> p_init) :
+			_data(p_init) {}
 };
 
 #endif // VSET_H

+ 18 - 0
tests/core/templates/test_a_hash_map.h

@@ -37,6 +37,24 @@
 
 namespace TestAHashMap {
 
+TEST_CASE("[AHashMap] List initialization") {
+	AHashMap<int, String> 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<int, String> 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<int, int> map;
 	AHashMap<int, int>::Iterator e = map.insert(42, 84);

+ 18 - 0
tests/core/templates/test_hash_map.h

@@ -37,6 +37,24 @@
 
 namespace TestHashMap {
 
+TEST_CASE("[HashMap] List initialization") {
+	HashMap<int, String> 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<int, String> 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<int, int> map;
 	HashMap<int, int>::Iterator e = map.insert(42, 84);

+ 18 - 0
tests/core/templates/test_hash_set.h

@@ -37,6 +37,24 @@
 
 namespace TestHashSet {
 
+TEST_CASE("[HashSet] List initialization") {
+	HashSet<int> 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<int> set{ 0, 0, 0, 0, 0 };
+
+	CHECK(set.size() == 1);
+	CHECK(set.has(0));
+}
+
 TEST_CASE("[HashSet] Insert element") {
 	HashSet<int> set;
 	HashSet<int>::Iterator e = set.insert(42);

+ 11 - 0
tests/core/templates/test_list.h

@@ -45,6 +45,17 @@ static void populate_integers(List<int> &p_list, List<int>::Element *r_elements[
 	}
 }
 
+TEST_CASE("[List] List initialization") {
+	List<int> 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<String> list;
 

+ 26 - 0
tests/core/templates/test_oa_hash_map.h

@@ -38,6 +38,32 @@
 
 namespace TestOAHashMap {
 
+TEST_CASE("[OAHashMap] List initialization") {
+	OAHashMap<int, String> 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<int, String> 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<int, int> map;
 	map.insert(42, 84);