瀏覽代碼

Port a bunch of Godot container templates to GDExtension.

bruvzg 3 年之前
父節點
當前提交
e36180f377

+ 2 - 0
binding_generator.py

@@ -222,6 +222,8 @@ def generate_builtin_class_header(builtin_api, size, used_classes, fully_used_cl
     # Special cases.
     if class_name == "String":
         result.append("#include <godot_cpp/variant/char_string.hpp>")
+        result.append("#include <godot_cpp/variant/char_utils.hpp>")
+        result.append("#include <godot_cpp/variant/ucaps.hpp>")
 
     if class_name == "Array":
         result.append("#include <godot_cpp/variant/array_helpers.hpp>")

+ 3 - 0
include/godot_cpp/core/class_db.hpp

@@ -209,6 +209,9 @@ MethodBind *ClassDB::bind_vararg_method(uint32_t p_flags, const char *p_name, M
 
 	return bind;
 }
+
+#define GDREGISTER_CLASS(m_class) ClassDB::register_class<m_class>();
+
 } // namespace godot
 
 #endif // ! CLASS_DB_HPP

+ 29 - 1
include/godot_cpp/core/math.hpp

@@ -62,6 +62,34 @@ namespace Math {
 #define Math_INF INFINITY
 #define Math_NAN NAN
 
+// Windows badly defines a lot of stuff we'll never use. Undefine it.
+#ifdef _WIN32
+#undef MIN // override standard definition
+#undef MAX // override standard definition
+#undef CLAMP // override standard definition
+#endif
+
+// Generic ABS function, for math uses please use Math::abs.
+#ifndef ABS
+#define ABS(m_v) (((m_v) < 0) ? (-(m_v)) : (m_v))
+#endif
+
+#ifndef SIGN
+#define SIGN(m_v) (((m_v) == 0) ? (0.0) : (((m_v) < 0) ? (-1.0) : (+1.0)))
+#endif
+
+#ifndef MIN
+#define MIN(m_a, m_b) (((m_a) < (m_b)) ? (m_a) : (m_b))
+#endif
+
+#ifndef MAX
+#define MAX(m_a, m_b) (((m_a) > (m_b)) ? (m_a) : (m_b))
+#endif
+
+#ifndef CLAMP
+#define CLAMP(m_a, m_min, m_max) (((m_a) < (m_min)) ? (m_min) : (((m_a) > (m_max)) ? m_max : m_a))
+#endif
+
 // Functions reproduced as in Godot's source code `math_funcs.h`.
 // Some are overloads to automatically support changing real_t into either double or float in the way Godot does.
 
@@ -435,7 +463,7 @@ inline int fast_ftoi(float a) {
 	: "m" (a));*/
 
 #else
-	b = lrintf(a); //assuming everything but msvc 2012 or earlier has lrint
+	b = lrintf(a); // assuming everything but msvc 2012 or earlier has lrint
 #endif
 	return b;
 }

+ 40 - 0
include/godot_cpp/core/memory.hpp

@@ -41,6 +41,7 @@
 #include <type_traits>
 
 void *operator new(size_t p_size, const char *p_description); ///< operator new that takes a description and uses MemoryStaticPool
+void *operator new(size_t p_size, void *(*p_allocfunc)(size_t p_size)); ///< operator new that takes a description and uses MemoryStaticPool
 void *operator new(size_t p_size, void *p_pointer, size_t check, const char *p_description); ///< operator new that takes a description and uses a pointer to the preallocated memory
 
 _ALWAYS_INLINE_ void *operator new(size_t p_size, void *p_pointer, size_t check, const char *p_description) {
@@ -76,10 +77,27 @@ _ALWAYS_INLINE_ T *_post_initialize(T *p_obj) {
 	return p_obj;
 }
 
+#define memalloc(m_size) Memory::alloc_static(m_size)
+#define memrealloc(m_mem, m_size) Memory::realloc_static(m_mem, m_size)
+#define memfree(m_mem) Memory::free_static(m_mem)
+
 #define memnew(m_class) _post_initialize(new ("") m_class)
 
+#define memnew_allocator(m_class, m_allocator) _post_initialize(new (m_allocator::alloc) m_class)
 #define memnew_placement(m_placement, m_class) _post_initialize(new (m_placement, sizeof(m_class), "") m_class)
 
+// Generic comparator used in Map, List, etc.
+template <class T>
+struct Comparator {
+	_ALWAYS_INLINE_ bool operator()(const T &p_a, const T &p_b) const { return (p_a < p_b); }
+};
+
+class DefaultAllocator {
+public:
+	_ALWAYS_INLINE_ static void *alloc(size_t p_memory) { return Memory::alloc_static(p_memory); }
+	_ALWAYS_INLINE_ static void free(void *p_ptr) { Memory::free_static(p_ptr); }
+};
+
 template <class T>
 void memdelete(T *p_class, typename std::enable_if<!std::is_base_of_v<godot::Wrapped, T>>::type * = 0) {
 	if (!__has_trivial_destructor(T)) {
@@ -94,6 +112,15 @@ void memdelete(T *p_class) {
 	godot::internal::gdn_interface->object_destroy(p_class->_owner);
 }
 
+template <class T, class A>
+void memdelete_allocator(T *p_class) {
+	if (!__has_trivial_destructor(T)) {
+		p_class->~T();
+	}
+
+	A::free(p_class);
+}
+
 #define memnew_arr(m_class, m_count) memnew_arr_template<m_class>(m_count)
 
 template <typename T>
@@ -137,6 +164,19 @@ void memdelete_arr(T *p_class) {
 	Memory::free_static(ptr);
 }
 
+struct _GlobalNil {
+	int color = 1;
+	_GlobalNil *right;
+	_GlobalNil *left;
+	_GlobalNil *parent;
+
+	_GlobalNil();
+};
+
+struct _GlobalNilClass {
+	static _GlobalNil _nil;
+};
+
 } // namespace godot
 
 #endif // ! GODOT_CPP_MEMORY_HPP

+ 59 - 0
include/godot_cpp/core/mutex_lock.hpp

@@ -0,0 +1,59 @@
+/*************************************************************************/
+/*  mutex_lock.hpp                                                       */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* 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 MUTEX_LOCK_HPP
+#define MUTEX_LOCK_HPP
+
+#include <godot_cpp/classes/mutex.hpp>
+
+namespace godot {
+
+class MutexLock {
+	const Mutex &mutex;
+
+public:
+	_ALWAYS_INLINE_ explicit MutexLock(const Mutex &p_mutex) :
+			mutex(p_mutex) {
+		const_cast<Mutex *>(&mutex)->lock();
+	}
+
+	_ALWAYS_INLINE_ ~MutexLock() {
+		const_cast<Mutex *>(&mutex)->unlock();
+	}
+};
+
+#define _THREAD_SAFE_CLASS_ mutable Mutex _thread_safe_;
+#define _THREAD_SAFE_METHOD_ MutexLock _thread_safe_method_(_thread_safe_);
+#define _THREAD_SAFE_LOCK_ _thread_safe_.lock();
+#define _THREAD_SAFE_UNLOCK_ _thread_safe_.unlock();
+
+} // namespace godot
+
+#endif // ! MUTEX_LOCK_HPP

+ 392 - 0
include/godot_cpp/templates/cowdata.hpp

@@ -0,0 +1,392 @@
+/*************************************************************************/
+/*  cowdata.hpp                                                          */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* 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 COWDATA_HPP
+#define COWDATA_HPP
+
+#include <godot_cpp/classes/global_constants.hpp>
+#include <godot_cpp/core/class_db.hpp>
+#include <godot_cpp/core/error_macros.hpp>
+#include <godot_cpp/core/math.hpp>
+#include <godot_cpp/core/memory.hpp>
+#include <godot_cpp/templates/safe_refcount.hpp>
+
+#include <cstring>
+
+namespace godot {
+
+template <class T>
+class Vector;
+
+template <class T, class V>
+class VMap;
+
+// Silence a false positive warning (see GH-52119).
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wplacement-new"
+#endif
+
+template <class T>
+class CowData {
+	template <class TV>
+	friend class Vector;
+
+	template <class TV, class VV>
+	friend class VMap;
+
+private:
+	mutable T *_ptr = nullptr;
+
+	// internal helpers
+
+	_FORCE_INLINE_ SafeNumeric<uint32_t> *_get_refcount() const {
+		if (!_ptr) {
+			return nullptr;
+		}
+
+		return reinterpret_cast<SafeNumeric<uint32_t> *>(_ptr) - 2;
+	}
+
+	_FORCE_INLINE_ uint32_t *_get_size() const {
+		if (!_ptr) {
+			return nullptr;
+		}
+
+		return reinterpret_cast<uint32_t *>(_ptr) - 1;
+	}
+
+	_FORCE_INLINE_ T *_get_data() const {
+		if (!_ptr) {
+			return nullptr;
+		}
+		return reinterpret_cast<T *>(_ptr);
+	}
+
+	_FORCE_INLINE_ size_t _get_alloc_size(size_t p_elements) const {
+		return Math::next_power_of_2(p_elements * sizeof(T));
+	}
+
+	_FORCE_INLINE_ bool _get_alloc_size_checked(size_t p_elements, size_t *out) const {
+#if defined(__GNUC__)
+		size_t o;
+		size_t p;
+		if (__builtin_mul_overflow(p_elements, sizeof(T), &o)) {
+			*out = 0;
+			return false;
+		}
+		*out = Math::next_power_of_2(o);
+		if (__builtin_add_overflow(o, static_cast<size_t>(32), &p)) {
+			return false; // No longer allocated here.
+		}
+		return true;
+#else
+		// Speed is more important than correctness here, do the operations unchecked
+		// and hope for the best.
+		*out = _get_alloc_size(p_elements);
+		return true;
+#endif
+	}
+
+	void _unref(void *p_data);
+	void _ref(const CowData *p_from);
+	void _ref(const CowData &p_from);
+	uint32_t _copy_on_write();
+
+public:
+	void operator=(const CowData<T> &p_from) { _ref(p_from); }
+
+	_FORCE_INLINE_ T *ptrw() {
+		_copy_on_write();
+		return (T *)_get_data();
+	}
+
+	_FORCE_INLINE_ const T *ptr() const {
+		return _get_data();
+	}
+
+	_FORCE_INLINE_ int size() const {
+		uint32_t *size = (uint32_t *)_get_size();
+		if (size) {
+			return *size;
+		} else {
+			return 0;
+		}
+	}
+
+	_FORCE_INLINE_ void clear() { resize(0); }
+	_FORCE_INLINE_ bool is_empty() const { return _ptr == nullptr; }
+
+	_FORCE_INLINE_ void set(int p_index, const T &p_elem) {
+		ERR_FAIL_INDEX(p_index, size());
+		_copy_on_write();
+		_get_data()[p_index] = p_elem;
+	}
+
+	_FORCE_INLINE_ T &get_m(int p_index) {
+		CRASH_BAD_INDEX(p_index, size());
+		_copy_on_write();
+		return _get_data()[p_index];
+	}
+
+	_FORCE_INLINE_ const T &get(int p_index) const {
+		CRASH_BAD_INDEX(p_index, size());
+
+		return _get_data()[p_index];
+	}
+
+	Error resize(int p_size);
+
+	_FORCE_INLINE_ void remove_at(int p_index) {
+		ERR_FAIL_INDEX(p_index, size());
+		T *p = ptrw();
+		int len = size();
+		for (int i = p_index; i < len - 1; i++) {
+			p[i] = p[i + 1];
+		}
+
+		resize(len - 1);
+	}
+
+	Error insert(int p_pos, const T &p_val) {
+		ERR_FAIL_INDEX_V(p_pos, size() + 1, ERR_INVALID_PARAMETER);
+		resize(size() + 1);
+		for (int i = (size() - 1); i > p_pos; i--) {
+			set(i, get(i - 1));
+		}
+		set(p_pos, p_val);
+
+		return OK;
+	}
+
+	int find(const T &p_val, int p_from = 0) const;
+
+	_FORCE_INLINE_ CowData() {}
+	_FORCE_INLINE_ ~CowData();
+	_FORCE_INLINE_ CowData(CowData<T> &p_from) { _ref(p_from); };
+};
+
+template <class T>
+void CowData<T>::_unref(void *p_data) {
+	if (!p_data) {
+		return;
+	}
+
+	SafeNumeric<uint32_t> *refc = _get_refcount();
+
+	if (refc->decrement() > 0) {
+		return; // still in use
+	}
+	// clean up
+
+	if (!__has_trivial_destructor(T)) {
+		uint32_t *count = _get_size();
+		T *data = (T *)(count + 1);
+
+		for (uint32_t i = 0; i < *count; ++i) {
+			// call destructors
+			data[i].~T();
+		}
+	}
+
+	// free mem
+	Memory::free_static((uint8_t *)p_data);
+}
+
+template <class T>
+uint32_t CowData<T>::_copy_on_write() {
+	if (!_ptr) {
+		return 0;
+	}
+
+	SafeNumeric<uint32_t> *refc = _get_refcount();
+
+	uint32_t rc = refc->get();
+	if (unlikely(rc > 1)) {
+		/* in use by more than me */
+		uint32_t current_size = *_get_size();
+
+		uint32_t *mem_new = (uint32_t *)Memory::alloc_static(_get_alloc_size(current_size));
+
+		new (mem_new - 2) SafeNumeric<uint32_t>(1); // refcount
+		*(mem_new - 1) = current_size; // size
+
+		T *_data = (T *)(mem_new);
+
+		// initialize new elements
+		if (__has_trivial_copy(T)) {
+			memcpy(mem_new, _ptr, current_size * sizeof(T));
+
+		} else {
+			for (uint32_t i = 0; i < current_size; i++) {
+				memnew_placement(&_data[i], T(_get_data()[i]));
+			}
+		}
+
+		_unref(_ptr);
+		_ptr = _data;
+
+		rc = 1;
+	}
+	return rc;
+}
+
+template <class T>
+Error CowData<T>::resize(int p_size) {
+	ERR_FAIL_COND_V(p_size < 0, ERR_INVALID_PARAMETER);
+
+	int current_size = size();
+
+	if (p_size == current_size) {
+		return OK;
+	}
+
+	if (p_size == 0) {
+		// wants to clean up
+		_unref(_ptr);
+		_ptr = nullptr;
+		return OK;
+	}
+
+	// possibly changing size, copy on write
+	uint32_t rc = _copy_on_write();
+
+	size_t current_alloc_size = _get_alloc_size(current_size);
+	size_t alloc_size;
+	ERR_FAIL_COND_V(!_get_alloc_size_checked(p_size, &alloc_size), ERR_OUT_OF_MEMORY);
+
+	if (p_size > current_size) {
+		if (alloc_size != current_alloc_size) {
+			if (current_size == 0) {
+				// alloc from scratch
+				uint32_t *ptr = (uint32_t *)Memory::alloc_static(alloc_size);
+				ERR_FAIL_COND_V(!ptr, ERR_OUT_OF_MEMORY);
+				*(ptr - 1) = 0; // size, currently none
+				new (ptr - 2) SafeNumeric<uint32_t>(1); // refcount
+
+				_ptr = (T *)ptr;
+
+			} else {
+				uint32_t *_ptrnew = (uint32_t *)Memory::realloc_static(_ptr, alloc_size);
+				ERR_FAIL_COND_V(!_ptrnew, ERR_OUT_OF_MEMORY);
+				new (_ptrnew - 2) SafeNumeric<uint32_t>(rc); // refcount
+
+				_ptr = (T *)(_ptrnew);
+			}
+		}
+
+		// construct the newly created elements
+
+		if (!__has_trivial_constructor(T)) {
+			T *elems = _get_data();
+
+			for (int i = *_get_size(); i < p_size; i++) {
+				memnew_placement(&elems[i], T);
+			}
+		}
+
+		*_get_size() = p_size;
+
+	} else if (p_size < current_size) {
+		if (!__has_trivial_destructor(T)) {
+			// deinitialize no longer needed elements
+			for (uint32_t i = p_size; i < *_get_size(); i++) {
+				T *t = &_get_data()[i];
+				t->~T();
+			}
+		}
+
+		if (alloc_size != current_alloc_size) {
+			uint32_t *_ptrnew = (uint32_t *)Memory::realloc_static(_ptr, alloc_size);
+			ERR_FAIL_COND_V(!_ptrnew, ERR_OUT_OF_MEMORY);
+			new (_ptrnew - 2) SafeNumeric<uint32_t>(rc); // refcount
+
+			_ptr = (T *)(_ptrnew);
+		}
+
+		*_get_size() = p_size;
+	}
+
+	return OK;
+}
+
+template <class T>
+int CowData<T>::find(const T &p_val, int p_from) const {
+	int ret = -1;
+
+	if (p_from < 0 || size() == 0) {
+		return ret;
+	}
+
+	for (int i = p_from; i < size(); i++) {
+		if (get(i) == p_val) {
+			ret = i;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+template <class T>
+void CowData<T>::_ref(const CowData *p_from) {
+	_ref(*p_from);
+}
+
+template <class T>
+void CowData<T>::_ref(const CowData &p_from) {
+	if (_ptr == p_from._ptr) {
+		return; // self assign, do nothing.
+	}
+
+	_unref(_ptr);
+	_ptr = nullptr;
+
+	if (!p_from._ptr) {
+		return; // nothing to do
+	}
+
+	if (p_from._get_refcount()->conditional_increment() > 0) { // could reference
+		_ptr = p_from._ptr;
+	}
+}
+
+template <class T>
+CowData<T>::~CowData() {
+	_unref(_ptr);
+}
+
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+} // namespace godot
+
+#endif // ! COWDATA_HPP

+ 557 - 0
include/godot_cpp/templates/hash_map.hpp

@@ -0,0 +1,557 @@
+/*************************************************************************/
+/*  hash_map.hpp                                                         */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* 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 HASH_MAP_HPP
+#define HASH_MAP_HPP
+
+#include <godot_cpp/core/error_macros.hpp>
+#include <godot_cpp/core/memory.hpp>
+#include <godot_cpp/templates/hashfuncs.hpp>
+#include <godot_cpp/templates/list.hpp>
+
+/**
+ * @class HashMap
+ *
+ * Implementation of a standard Hashing HashMap, for quick lookups of Data associated with a Key.
+ * The implementation provides hashers for the default types, if you need a special kind of hasher, provide
+ * your own.
+ * @param TKey  Key, search is based on it, needs to be hasheable. It is unique in this container.
+ * @param TData Data, data associated with the key
+ * @param Hasher Hasher object, needs to provide a valid static hash function for TKey
+ * @param Comparator comparator object, needs to be able to safely compare two TKey values.
+ * It needs to ensure that x == x for any items inserted in the map. Bear in mind that nan != nan when implementing an equality check.
+ * @param MIN_HASH_TABLE_POWER Miminum size of the hash table, as a power of two. You rarely need to change this parameter.
+ * @param RELATIONSHIP Relationship at which the hash table is resized. if amount of elements is RELATIONSHIP
+ * times bigger than the hash table, table is resized to solve this condition. if RELATIONSHIP is zero, table is always MIN_HASH_TABLE_POWER.
+ *
+ */
+
+namespace godot {
+
+template <class TKey, class TData, class Hasher = HashMapHasherDefault, class Comparator = HashMapComparatorDefault<TKey>, uint8_t MIN_HASH_TABLE_POWER = 3, uint8_t RELATIONSHIP = 8>
+class HashMap {
+public:
+	struct Pair {
+		TKey key;
+		TData data;
+
+		Pair(const TKey &p_key) :
+				key(p_key),
+				data() {}
+		Pair(const TKey &p_key, const TData &p_data) :
+				key(p_key),
+				data(p_data) {
+		}
+	};
+
+	struct Element {
+	private:
+		friend class HashMap;
+
+		uint32_t hash = 0;
+		Element *next = nullptr;
+		Element() {}
+		Pair pair;
+
+	public:
+		const TKey &key() const {
+			return pair.key;
+		}
+
+		TData &value() {
+			return pair.data;
+		}
+
+		const TData &value() const {
+			return pair.value();
+		}
+
+		Element(const TKey &p_key) :
+				pair(p_key) {}
+		Element(const Element &p_other) :
+				hash(p_other.hash),
+				pair(p_other.pair.key, p_other.pair.data) {}
+	};
+
+private:
+	Element **hash_table = nullptr;
+	uint8_t hash_table_power = 0;
+	uint32_t elements = 0;
+
+	void make_hash_table() {
+		ERR_FAIL_COND(hash_table);
+
+		hash_table = memnew_arr(Element *, (1 << MIN_HASH_TABLE_POWER));
+
+		hash_table_power = MIN_HASH_TABLE_POWER;
+		elements = 0;
+		for (int i = 0; i < (1 << MIN_HASH_TABLE_POWER); i++) {
+			hash_table[i] = nullptr;
+		}
+	}
+
+	void erase_hash_table() {
+		ERR_FAIL_COND_MSG(elements, "Cannot erase hash table if there are still elements inside.");
+
+		memdelete_arr(hash_table);
+		hash_table = nullptr;
+		hash_table_power = 0;
+		elements = 0;
+	}
+
+	void check_hash_table() {
+		int new_hash_table_power = -1;
+
+		if ((int)elements > ((1 << hash_table_power) * RELATIONSHIP)) {
+			/* rehash up */
+			new_hash_table_power = hash_table_power + 1;
+
+			while ((int)elements > ((1 << new_hash_table_power) * RELATIONSHIP)) {
+				new_hash_table_power++;
+			}
+
+		} else if ((hash_table_power > (int)MIN_HASH_TABLE_POWER) && ((int)elements < ((1 << (hash_table_power - 1)) * RELATIONSHIP))) {
+			/* rehash down */
+			new_hash_table_power = hash_table_power - 1;
+
+			while ((int)elements < ((1 << (new_hash_table_power - 1)) * RELATIONSHIP)) {
+				new_hash_table_power--;
+			}
+
+			if (new_hash_table_power < (int)MIN_HASH_TABLE_POWER) {
+				new_hash_table_power = MIN_HASH_TABLE_POWER;
+			}
+		}
+
+		if (new_hash_table_power == -1) {
+			return;
+		}
+
+		Element **new_hash_table = memnew_arr(Element *, ((uint64_t)1 << new_hash_table_power));
+		ERR_FAIL_COND_MSG(!new_hash_table, "Out of memory.");
+
+		for (int i = 0; i < (1 << new_hash_table_power); i++) {
+			new_hash_table[i] = nullptr;
+		}
+
+		if (hash_table) {
+			for (int i = 0; i < (1 << hash_table_power); i++) {
+				while (hash_table[i]) {
+					Element *se = hash_table[i];
+					hash_table[i] = se->next;
+					int new_pos = se->hash & ((1 << new_hash_table_power) - 1);
+					se->next = new_hash_table[new_pos];
+					new_hash_table[new_pos] = se;
+				}
+			}
+
+			memdelete_arr(hash_table);
+		}
+		hash_table = new_hash_table;
+		hash_table_power = new_hash_table_power;
+	}
+
+	/* I want to have only one function.. */
+	_FORCE_INLINE_ const Element *get_element(const TKey &p_key) const {
+		uint32_t hash = Hasher::hash(p_key);
+		uint32_t index = hash & ((1 << hash_table_power) - 1);
+
+		Element *e = hash_table[index];
+
+		while (e) {
+			/* checking hash first avoids comparing key, which may take longer */
+			if (e->hash == hash && Comparator::compare(e->pair.key, p_key)) {
+				/* the pair exists in this hashtable, so just update data */
+				return e;
+			}
+
+			e = e->next;
+		}
+
+		return nullptr;
+	}
+
+	Element *create_element(const TKey &p_key) {
+		/* if element doesn't exist, create it */
+		Element *e = memnew(Element(p_key));
+		ERR_FAIL_COND_V_MSG(!e, nullptr, "Out of memory.");
+		uint32_t hash = Hasher::hash(p_key);
+		uint32_t index = hash & ((1 << hash_table_power) - 1);
+		e->next = hash_table[index];
+		e->hash = hash;
+
+		hash_table[index] = e;
+		elements++;
+
+		return e;
+	}
+
+	void copy_from(const HashMap &p_t) {
+		if (&p_t == this) {
+			return; /* much less bother with that */
+		}
+
+		clear();
+
+		if (!p_t.hash_table || p_t.hash_table_power == 0) {
+			return; /* not copying from empty table */
+		}
+
+		hash_table = memnew_arr(Element *, (uint64_t)1 << p_t.hash_table_power);
+		hash_table_power = p_t.hash_table_power;
+		elements = p_t.elements;
+
+		for (int i = 0; i < (1 << p_t.hash_table_power); i++) {
+			hash_table[i] = nullptr;
+
+			const Element *e = p_t.hash_table[i];
+
+			while (e) {
+				Element *le = memnew(Element(*e)); /* local element */
+
+				/* add to list and reassign pointers */
+				le->next = hash_table[i];
+				hash_table[i] = le;
+
+				e = e->next;
+			}
+		}
+	}
+
+public:
+	Element *set(const TKey &p_key, const TData &p_data) {
+		return set(Pair(p_key, p_data));
+	}
+
+	Element *set(const Pair &p_pair) {
+		Element *e = nullptr;
+		if (!hash_table) {
+			make_hash_table(); // if no table, make one
+		} else {
+			e = const_cast<Element *>(get_element(p_pair.key));
+		}
+
+		/* if we made it up to here, the pair doesn't exist, create and assign */
+
+		if (!e) {
+			e = create_element(p_pair.key);
+			if (!e) {
+				return nullptr;
+			}
+			check_hash_table(); // perform mantenience routine
+		}
+
+		e->pair.data = p_pair.data;
+		return e;
+	}
+
+	bool has(const TKey &p_key) const {
+		return getptr(p_key) != nullptr;
+	}
+
+	/**
+	 * Get a key from data, return a const reference.
+	 * WARNING: this doesn't check errors, use either getptr and check nullptr, or check
+	 * first with has(key)
+	 */
+
+	const TData &get(const TKey &p_key) const {
+		const TData *res = getptr(p_key);
+		CRASH_COND_MSG(!res, "Map key not found.");
+		return *res;
+	}
+
+	TData &get(const TKey &p_key) {
+		TData *res = getptr(p_key);
+		CRASH_COND_MSG(!res, "Map key not found.");
+		return *res;
+	}
+
+	/**
+	 * Same as get, except it can return nullptr when item was not found.
+	 * This is mainly used for speed purposes.
+	 */
+
+	_FORCE_INLINE_ TData *getptr(const TKey &p_key) {
+		if (unlikely(!hash_table)) {
+			return nullptr;
+		}
+
+		Element *e = const_cast<Element *>(get_element(p_key));
+
+		if (e) {
+			return &e->pair.data;
+		}
+
+		return nullptr;
+	}
+
+	_FORCE_INLINE_ const TData *getptr(const TKey &p_key) const {
+		if (unlikely(!hash_table)) {
+			return nullptr;
+		}
+
+		const Element *e = const_cast<Element *>(get_element(p_key));
+
+		if (e) {
+			return &e->pair.data;
+		}
+
+		return nullptr;
+	}
+
+	/**
+	 * Same as get, except it can return nullptr when item was not found.
+	 * This version is custom, will take a hash and a custom key (that should support operator==()
+	 */
+
+	template <class C>
+	_FORCE_INLINE_ TData *custom_getptr(C p_custom_key, uint32_t p_custom_hash) {
+		if (unlikely(!hash_table)) {
+			return nullptr;
+		}
+
+		uint32_t hash = p_custom_hash;
+		uint32_t index = hash & ((1 << hash_table_power) - 1);
+
+		Element *e = hash_table[index];
+
+		while (e) {
+			/* checking hash first avoids comparing key, which may take longer */
+			if (e->hash == hash && Comparator::compare(e->pair.key, p_custom_key)) {
+				/* the pair exists in this hashtable, so just update data */
+				return &e->pair.data;
+			}
+
+			e = e->next;
+		}
+
+		return nullptr;
+	}
+
+	template <class C>
+	_FORCE_INLINE_ const TData *custom_getptr(C p_custom_key, uint32_t p_custom_hash) const {
+		if (unlikely(!hash_table)) {
+			return nullptr;
+		}
+
+		uint32_t hash = p_custom_hash;
+		uint32_t index = hash & ((1 << hash_table_power) - 1);
+
+		const Element *e = hash_table[index];
+
+		while (e) {
+			/* checking hash first avoids comparing key, which may take longer */
+			if (e->hash == hash && Comparator::compare(e->pair.key, p_custom_key)) {
+				/* the pair exists in this hashtable, so just update data */
+				return &e->pair.data;
+			}
+
+			e = e->next;
+		}
+
+		return nullptr;
+	}
+
+	/**
+	 * Erase an item, return true if erasing was successful
+	 */
+
+	bool erase(const TKey &p_key) {
+		if (unlikely(!hash_table)) {
+			return false;
+		}
+
+		uint32_t hash = Hasher::hash(p_key);
+		uint32_t index = hash & ((1 << hash_table_power) - 1);
+
+		Element *e = hash_table[index];
+		Element *p = nullptr;
+		while (e) {
+			/* checking hash first avoids comparing key, which may take longer */
+			if (e->hash == hash && Comparator::compare(e->pair.key, p_key)) {
+				if (p) {
+					p->next = e->next;
+				} else {
+					// begin of list
+					hash_table[index] = e->next;
+				}
+
+				memdelete(e);
+				elements--;
+
+				if (elements == 0) {
+					erase_hash_table();
+				} else {
+					check_hash_table();
+				}
+				return true;
+			}
+
+			p = e;
+			e = e->next;
+		}
+
+		return false;
+	}
+
+	inline const TData &operator[](const TKey &p_key) const { // constref
+
+		return get(p_key);
+	}
+	inline TData &operator[](const TKey &p_key) { // assignment
+
+		Element *e = nullptr;
+		if (!hash_table) {
+			make_hash_table(); // if no table, make one
+		} else {
+			e = const_cast<Element *>(get_element(p_key));
+		}
+
+		/* if we made it up to here, the pair doesn't exist, create */
+		if (!e) {
+			e = create_element(p_key);
+			CRASH_COND(!e);
+			check_hash_table(); // perform mantenience routine
+		}
+
+		return e->pair.data;
+	}
+
+	/**
+	 * Get the next key to p_key, and the first key if p_key is null.
+	 * Returns a pointer to the next key if found, nullptr otherwise.
+	 * Adding/Removing elements while iterating will, of course, have unexpected results, don't do it.
+	 *
+	 * Example:
+	 *
+	 * 	const TKey *k=nullptr;
+	 *
+	 * 	while( (k=table.next(k)) ) {
+	 *
+	 * 		print( *k );
+	 * 	}
+	 *
+	 */
+	const TKey *next(const TKey *p_key) const {
+		if (unlikely(!hash_table)) {
+			return nullptr;
+		}
+
+		if (!p_key) { /* get the first key */
+
+			for (int i = 0; i < (1 << hash_table_power); i++) {
+				if (hash_table[i]) {
+					return &hash_table[i]->pair.key;
+				}
+			}
+
+		} else { /* get the next key */
+
+			const Element *e = get_element(*p_key);
+			ERR_FAIL_COND_V_MSG(!e, nullptr, "Invalid key supplied.");
+			if (e->next) {
+				/* if there is a "next" in the list, return that */
+				return &e->next->pair.key;
+			} else {
+				/* go to next elements */
+				uint32_t index = e->hash & ((1 << hash_table_power) - 1);
+				index++;
+				for (int i = index; i < (1 << hash_table_power); i++) {
+					if (hash_table[i]) {
+						return &hash_table[i]->pair.key;
+					}
+				}
+			}
+
+			/* nothing found, was at end */
+		}
+
+		return nullptr; /* nothing found */
+	}
+
+	inline unsigned int size() const {
+		return elements;
+	}
+
+	inline bool is_empty() const {
+		return elements == 0;
+	}
+
+	void clear() {
+		/* clean up */
+		if (hash_table) {
+			for (int i = 0; i < (1 << hash_table_power); i++) {
+				while (hash_table[i]) {
+					Element *e = hash_table[i];
+					hash_table[i] = e->next;
+					memdelete(e);
+				}
+			}
+
+			memdelete_arr(hash_table);
+		}
+
+		hash_table = nullptr;
+		hash_table_power = 0;
+		elements = 0;
+	}
+
+	void operator=(const HashMap &p_table) {
+		copy_from(p_table);
+	}
+
+	void get_key_list(List<TKey> *r_keys) const {
+		if (unlikely(!hash_table)) {
+			return;
+		}
+		for (int i = 0; i < (1 << hash_table_power); i++) {
+			Element *e = hash_table[i];
+			while (e) {
+				r_keys->push_back(e->pair.key);
+				e = e->next;
+			}
+		}
+	}
+
+	HashMap() {}
+
+	HashMap(const HashMap &p_table) {
+		copy_from(p_table);
+	}
+
+	~HashMap() {
+		clear();
+	}
+};
+
+} // namespace godot
+
+#endif // ! HASH_MAP_HPP

+ 191 - 0
include/godot_cpp/templates/hashfuncs.hpp

@@ -0,0 +1,191 @@
+/*************************************************************************/
+/*  hashfuncs.hpp                                                        */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* 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 HASHFUNCS_HPP
+#define HASHFUNCS_HPP
+
+#include <godot_cpp/core/math.hpp>
+#include <godot_cpp/variant/rid.hpp>
+
+/**
+ * Hashing functions
+ */
+
+namespace godot {
+
+/**
+ * DJB2 Hash function
+ * @param C String
+ * @return 32-bits hashcode
+ */
+static inline uint32_t hash_djb2(const char *p_cstr) {
+	const unsigned char *chr = (const unsigned char *)p_cstr;
+	uint32_t hash = 5381;
+	uint32_t c;
+
+	while ((c = *chr++)) {
+		hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
+	}
+
+	return hash;
+}
+
+static inline uint32_t hash_djb2_buffer(const uint8_t *p_buff, int p_len, uint32_t p_prev = 5381) {
+	uint32_t hash = p_prev;
+
+	for (int i = 0; i < p_len; i++) {
+		hash = ((hash << 5) + hash) + p_buff[i]; /* hash * 33 + c */
+	}
+
+	return hash;
+}
+
+static inline uint32_t hash_djb2_one_32(uint32_t p_in, uint32_t p_prev = 5381) {
+	return ((p_prev << 5) + p_prev) + p_in;
+}
+
+/**
+ * Thomas Wang's 64-bit to 32-bit Hash function:
+ * https://web.archive.org/web/20071223173210/https:/www.concentric.net/~Ttwang/tech/inthash.htm
+ *
+ * @param p_int - 64-bit unsigned integer key to be hashed
+ * @return unsigned 32-bit value representing hashcode
+ */
+static inline uint32_t hash_one_uint64(const uint64_t p_int) {
+	uint64_t v = p_int;
+	v = (~v) + (v << 18); // v = (v << 18) - v - 1;
+	v = v ^ (v >> 31);
+	v = v * 21; // v = (v + (v << 2)) + (v << 4);
+	v = v ^ (v >> 11);
+	v = v + (v << 6);
+	v = v ^ (v >> 22);
+	return uint32_t(v);
+}
+
+static inline uint32_t hash_djb2_one_float(double p_in, uint32_t p_prev = 5381) {
+	union {
+		double d;
+		uint64_t i;
+	} u;
+
+	// Normalize +/- 0.0 and NaN values so they hash the same.
+	if (p_in == 0.0f) {
+		u.d = 0.0;
+	} else if (std::isnan(p_in)) {
+		u.d = NAN;
+	} else {
+		u.d = p_in;
+	}
+
+	return ((p_prev << 5) + p_prev) + hash_one_uint64(u.i);
+}
+
+template <class T>
+static inline uint32_t make_uint32_t(T p_in) {
+	union {
+		T t;
+		uint32_t _u32;
+	} _u;
+	_u._u32 = 0;
+	_u.t = p_in;
+	return _u._u32;
+}
+
+static inline uint64_t hash_djb2_one_float_64(double p_in, uint64_t p_prev = 5381) {
+	union {
+		double d;
+		uint64_t i;
+	} u;
+
+	// Normalize +/- 0.0 and NaN values so they hash the same.
+	if (p_in == 0.0f) {
+		u.d = 0.0;
+	} else if (std::isnan(p_in)) {
+		u.d = NAN;
+	} else {
+		u.d = p_in;
+	}
+
+	return ((p_prev << 5) + p_prev) + u.i;
+}
+
+static inline uint64_t hash_djb2_one_64(uint64_t p_in, uint64_t p_prev = 5381) {
+	return ((p_prev << 5) + p_prev) + p_in;
+}
+
+template <class T>
+static inline uint64_t make_uint64_t(T p_in) {
+	union {
+		T t;
+		uint64_t _u64;
+	} _u;
+	_u._u64 = 0; // in case p_in is smaller
+
+	_u.t = p_in;
+	return _u._u64;
+}
+
+struct HashMapHasherDefault {
+	static _FORCE_INLINE_ uint32_t hash(const char *p_cstr) { return hash_djb2(p_cstr); }
+	static _FORCE_INLINE_ uint32_t hash(const uint64_t p_int) { return hash_one_uint64(p_int); }
+
+	static _FORCE_INLINE_ uint32_t hash(const int64_t p_int) { return hash(uint64_t(p_int)); }
+	static _FORCE_INLINE_ uint32_t hash(const float p_float) { return hash_djb2_one_float(p_float); }
+	static _FORCE_INLINE_ uint32_t hash(const double p_double) { return hash_djb2_one_float(p_double); }
+	static _FORCE_INLINE_ uint32_t hash(const uint32_t p_int) { return p_int; }
+	static _FORCE_INLINE_ uint32_t hash(const int32_t p_int) { return (uint32_t)p_int; }
+	static _FORCE_INLINE_ uint32_t hash(const uint16_t p_int) { return p_int; }
+	static _FORCE_INLINE_ uint32_t hash(const int16_t p_int) { return (uint32_t)p_int; }
+	static _FORCE_INLINE_ uint32_t hash(const uint8_t p_int) { return p_int; }
+	static _FORCE_INLINE_ uint32_t hash(const int8_t p_int) { return (uint32_t)p_int; }
+	static _FORCE_INLINE_ uint32_t hash(const wchar_t p_wchar) { return (uint32_t)p_wchar; }
+	static _FORCE_INLINE_ uint32_t hash(const char16_t p_uchar) { return (uint32_t)p_uchar; }
+	static _FORCE_INLINE_ uint32_t hash(const char32_t p_uchar) { return (uint32_t)p_uchar; }
+	static _FORCE_INLINE_ uint32_t hash(const RID &p_rid) { return hash_one_uint64(p_rid.get_id()); }
+};
+
+template <typename T>
+struct HashMapComparatorDefault {
+	static bool compare(const T &p_lhs, const T &p_rhs) {
+		return p_lhs == p_rhs;
+	}
+
+	bool compare(const float &p_lhs, const float &p_rhs) {
+		return (p_lhs == p_rhs) || (std::isnan(p_lhs) && std::isnan(p_rhs));
+	}
+
+	bool compare(const double &p_lhs, const double &p_rhs) {
+		return (p_lhs == p_rhs) || (std::isnan(p_lhs) && std::isnan(p_rhs));
+	}
+};
+
+} // namespace godot
+
+#endif // ! HASHFUNCS_HPP

+ 769 - 0
include/godot_cpp/templates/list.hpp

@@ -0,0 +1,769 @@
+/*************************************************************************/
+/*  list.hpp                                                             */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* 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 LIST_HPP
+#define LIST_HPP
+
+#include <godot_cpp/core/error_macros.hpp>
+#include <godot_cpp/core/memory.hpp>
+#include <godot_cpp/templates/sort_array.hpp>
+
+/**
+ * Generic Templatized Linked List Implementation.
+ * The implementation differs from the STL one because
+ * a compatible preallocated linked list can be written
+ * using the same API, or features such as erasing an element
+ * from the iterator.
+ */
+
+namespace godot {
+
+template <class T, class A = DefaultAllocator>
+class List {
+	struct _Data;
+
+public:
+	class Element {
+	private:
+		friend class List<T, A>;
+
+		T value;
+		Element *next_ptr = nullptr;
+		Element *prev_ptr = nullptr;
+		_Data *data = nullptr;
+
+	public:
+		/**
+		 * Get NEXT Element iterator, for constant lists.
+		 */
+		_FORCE_INLINE_ const Element *next() const {
+			return next_ptr;
+		}
+		/**
+		 * Get NEXT Element iterator,
+		 */
+		_FORCE_INLINE_ Element *next() {
+			return next_ptr;
+		}
+
+		/**
+		 * Get PREV Element iterator, for constant lists.
+		 */
+		_FORCE_INLINE_ const Element *prev() const {
+			return prev_ptr;
+		}
+		/**
+		 * Get PREV Element iterator,
+		 */
+		_FORCE_INLINE_ Element *prev() {
+			return prev_ptr;
+		}
+
+		/**
+		 * * operator, for using as *iterator, when iterators are defined on stack.
+		 */
+		_FORCE_INLINE_ const T &operator*() const {
+			return value;
+		}
+		/**
+		 * operator->, for using as iterator->, when iterators are defined on stack, for constant lists.
+		 */
+		_FORCE_INLINE_ const T *operator->() const {
+			return &value;
+		}
+		/**
+		 * * operator, for using as *iterator, when iterators are defined on stack,
+		 */
+		_FORCE_INLINE_ T &operator*() {
+			return value;
+		}
+		/**
+		 * operator->, for using as iterator->, when iterators are defined on stack, for constant lists.
+		 */
+		_FORCE_INLINE_ T *operator->() {
+			return &value;
+		}
+
+		/**
+		 * get the value stored in this element.
+		 */
+		_FORCE_INLINE_ T &get() {
+			return value;
+		}
+		/**
+		 * get the value stored in this element, for constant lists
+		 */
+		_FORCE_INLINE_ const T &get() const {
+			return value;
+		}
+		/**
+		 * set the value stored in this element.
+		 */
+		_FORCE_INLINE_ void set(const T &p_value) {
+			value = (T &)p_value;
+		}
+
+		void erase() {
+			data->erase(this);
+		}
+
+		_FORCE_INLINE_ Element() {}
+	};
+
+	typedef T ValueType;
+
+	struct Iterator {
+		_FORCE_INLINE_ T &operator*() const {
+			return E->get();
+		}
+		_FORCE_INLINE_ T *operator->() const { return &E->get(); }
+		_FORCE_INLINE_ Iterator &operator++() {
+			E = E->next();
+			return *this;
+		}
+		_FORCE_INLINE_ Iterator &operator--() {
+			E = E->prev();
+			return *this;
+		}
+
+		_FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
+		_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
+
+		Iterator(Element *p_E) { E = p_E; }
+		Iterator() {}
+		Iterator(const Iterator &p_it) { E = p_it.E; }
+
+	private:
+		Element *E = nullptr;
+	};
+
+	struct ConstIterator {
+		_FORCE_INLINE_ const T &operator*() const {
+			return E->get();
+		}
+		_FORCE_INLINE_ const T *operator->() const { return &E->get(); }
+		_FORCE_INLINE_ ConstIterator &operator++() {
+			E = E->next();
+			return *this;
+		}
+		_FORCE_INLINE_ ConstIterator &operator--() {
+			E = E->prev();
+			return *this;
+		}
+
+		_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return E == b.E; }
+		_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return E != b.E; }
+
+		_FORCE_INLINE_ ConstIterator(const Element *p_E) { E = p_E; }
+		_FORCE_INLINE_ ConstIterator() {}
+		_FORCE_INLINE_ ConstIterator(const ConstIterator &p_it) { E = p_it.E; }
+
+	private:
+		const Element *E = nullptr;
+	};
+
+	_FORCE_INLINE_ Iterator begin() {
+		return Iterator(front());
+	}
+	_FORCE_INLINE_ Iterator end() {
+		return Iterator(nullptr);
+	}
+
+#if 0
+	//to use when replacing find()
+	_FORCE_INLINE_ Iterator find(const K &p_key) {
+		return Iterator(find(p_key));
+	}
+#endif
+	_FORCE_INLINE_ ConstIterator begin() const {
+		return ConstIterator(front());
+	}
+	_FORCE_INLINE_ ConstIterator end() const {
+		return ConstIterator(nullptr);
+	}
+#if 0
+	//to use when replacing find()
+	_FORCE_INLINE_ ConstIterator find(const K &p_key) const {
+		return ConstIterator(find(p_key));
+	}
+#endif
+private:
+	struct _Data {
+		Element *first = nullptr;
+		Element *last = nullptr;
+		int size_cache = 0;
+
+		bool erase(const Element *p_I) {
+			ERR_FAIL_COND_V(!p_I, false);
+			ERR_FAIL_COND_V(p_I->data != this, false);
+
+			if (first == p_I) {
+				first = p_I->next_ptr;
+			}
+
+			if (last == p_I) {
+				last = p_I->prev_ptr;
+			}
+
+			if (p_I->prev_ptr) {
+				p_I->prev_ptr->next_ptr = p_I->next_ptr;
+			}
+
+			if (p_I->next_ptr) {
+				p_I->next_ptr->prev_ptr = p_I->prev_ptr;
+			}
+
+			memdelete_allocator<Element, A>(const_cast<Element *>(p_I));
+			size_cache--;
+
+			return true;
+		}
+	};
+
+	_Data *_data = nullptr;
+
+public:
+	/**
+	 * return a const iterator to the beginning of the list.
+	 */
+	_FORCE_INLINE_ const Element *front() const {
+		return _data ? _data->first : nullptr;
+	}
+
+	/**
+	 * return an iterator to the beginning of the list.
+	 */
+	_FORCE_INLINE_ Element *front() {
+		return _data ? _data->first : nullptr;
+	}
+
+	/**
+	 * return a const iterator to the last member of the list.
+	 */
+	_FORCE_INLINE_ const Element *back() const {
+		return _data ? _data->last : nullptr;
+	}
+
+	/**
+	 * return an iterator to the last member of the list.
+	 */
+	_FORCE_INLINE_ Element *back() {
+		return _data ? _data->last : nullptr;
+	}
+
+	/**
+	 * store a new element at the end of the list
+	 */
+	Element *push_back(const T &value) {
+		if (!_data) {
+			_data = memnew_allocator(_Data, A);
+			_data->first = nullptr;
+			_data->last = nullptr;
+			_data->size_cache = 0;
+		}
+
+		Element *n = memnew_allocator(Element, A);
+		n->value = (T &)value;
+
+		n->prev_ptr = _data->last;
+		n->next_ptr = nullptr;
+		n->data = _data;
+
+		if (_data->last) {
+			_data->last->next_ptr = n;
+		}
+
+		_data->last = n;
+
+		if (!_data->first) {
+			_data->first = n;
+		}
+
+		_data->size_cache++;
+
+		return n;
+	}
+
+	void pop_back() {
+		if (_data && _data->last) {
+			erase(_data->last);
+		}
+	}
+
+	/**
+	 * store a new element at the beginning of the list
+	 */
+	Element *push_front(const T &value) {
+		if (!_data) {
+			_data = memnew_allocator(_Data, A);
+			_data->first = nullptr;
+			_data->last = nullptr;
+			_data->size_cache = 0;
+		}
+
+		Element *n = memnew_allocator(Element, A);
+		n->value = (T &)value;
+		n->prev_ptr = nullptr;
+		n->next_ptr = _data->first;
+		n->data = _data;
+
+		if (_data->first) {
+			_data->first->prev_ptr = n;
+		}
+
+		_data->first = n;
+
+		if (!_data->last) {
+			_data->last = n;
+		}
+
+		_data->size_cache++;
+
+		return n;
+	}
+
+	void pop_front() {
+		if (_data && _data->first) {
+			erase(_data->first);
+		}
+	}
+
+	Element *insert_after(Element *p_element, const T &p_value) {
+		CRASH_COND(p_element && (!_data || p_element->data != _data));
+
+		if (!p_element) {
+			return push_back(p_value);
+		}
+
+		Element *n = memnew_allocator(Element, A);
+		n->value = (T &)p_value;
+		n->prev_ptr = p_element;
+		n->next_ptr = p_element->next_ptr;
+		n->data = _data;
+
+		if (!p_element->next_ptr) {
+			_data->last = n;
+		} else {
+			p_element->next_ptr->prev_ptr = n;
+		}
+
+		p_element->next_ptr = n;
+
+		_data->size_cache++;
+
+		return n;
+	}
+
+	Element *insert_before(Element *p_element, const T &p_value) {
+		CRASH_COND(p_element && (!_data || p_element->data != _data));
+
+		if (!p_element) {
+			return push_back(p_value);
+		}
+
+		Element *n = memnew_allocator(Element, A);
+		n->value = (T &)p_value;
+		n->prev_ptr = p_element->prev_ptr;
+		n->next_ptr = p_element;
+		n->data = _data;
+
+		if (!p_element->prev_ptr) {
+			_data->first = n;
+		} else {
+			p_element->prev_ptr->next_ptr = n;
+		}
+
+		p_element->prev_ptr = n;
+
+		_data->size_cache++;
+
+		return n;
+	}
+
+	/**
+	 * find an element in the list,
+	 */
+	template <class T_v>
+	Element *find(const T_v &p_val) {
+		Element *it = front();
+		while (it) {
+			if (it->value == p_val) {
+				return it;
+			}
+			it = it->next();
+		}
+
+		return nullptr;
+	}
+
+	/**
+	 * erase an element in the list, by iterator pointing to it. Return true if it was found/erased.
+	 */
+	bool erase(const Element *p_I) {
+		if (_data && p_I) {
+			bool ret = _data->erase(p_I);
+
+			if (_data->size_cache == 0) {
+				memdelete_allocator<_Data, A>(_data);
+				_data = nullptr;
+			}
+
+			return ret;
+		}
+
+		return false;
+	}
+
+	/**
+	 * erase the first element in the list, that contains value
+	 */
+	bool erase(const T &value) {
+		Element *I = find(value);
+		return erase(I);
+	}
+
+	/**
+	 * return whether the list is empty
+	 */
+	_FORCE_INLINE_ bool is_empty() const {
+		return (!_data || !_data->size_cache);
+	}
+
+	/**
+	 * clear the list
+	 */
+	void clear() {
+		while (front()) {
+			erase(front());
+		}
+	}
+
+	_FORCE_INLINE_ int size() const {
+		return _data ? _data->size_cache : 0;
+	}
+
+	void swap(Element *p_A, Element *p_B) {
+		ERR_FAIL_COND(!p_A || !p_B);
+		ERR_FAIL_COND(p_A->data != _data);
+		ERR_FAIL_COND(p_B->data != _data);
+
+		if (p_A == p_B) {
+			return;
+		}
+		Element *A_prev = p_A->prev_ptr;
+		Element *A_next = p_A->next_ptr;
+		Element *B_prev = p_B->prev_ptr;
+		Element *B_next = p_B->next_ptr;
+
+		if (A_prev) {
+			A_prev->next_ptr = p_B;
+		} else {
+			_data->first = p_B;
+		}
+		if (B_prev) {
+			B_prev->next_ptr = p_A;
+		} else {
+			_data->first = p_A;
+		}
+		if (A_next) {
+			A_next->prev_ptr = p_B;
+		} else {
+			_data->last = p_B;
+		}
+		if (B_next) {
+			B_next->prev_ptr = p_A;
+		} else {
+			_data->last = p_A;
+		}
+		p_A->prev_ptr = A_next == p_B ? p_B : B_prev;
+		p_A->next_ptr = B_next == p_A ? p_B : B_next;
+		p_B->prev_ptr = B_next == p_A ? p_A : A_prev;
+		p_B->next_ptr = A_next == p_B ? p_A : A_next;
+	}
+	/**
+	 * copy the list
+	 */
+	void operator=(const List &p_list) {
+		clear();
+		const Element *it = p_list.front();
+		while (it) {
+			push_back(it->get());
+			it = it->next();
+		}
+	}
+
+	T &operator[](int p_index) {
+		CRASH_BAD_INDEX(p_index, size());
+
+		Element *I = front();
+		int c = 0;
+		while (c < p_index) {
+			I = I->next();
+			c++;
+		}
+
+		return I->get();
+	}
+
+	const T &operator[](int p_index) const {
+		CRASH_BAD_INDEX(p_index, size());
+
+		const Element *I = front();
+		int c = 0;
+		while (c < p_index) {
+			I = I->next();
+			c++;
+		}
+
+		return I->get();
+	}
+
+	void move_to_back(Element *p_I) {
+		ERR_FAIL_COND(p_I->data != _data);
+		if (!p_I->next_ptr) {
+			return;
+		}
+
+		if (_data->first == p_I) {
+			_data->first = p_I->next_ptr;
+		}
+
+		if (_data->last == p_I) {
+			_data->last = p_I->prev_ptr;
+		}
+
+		if (p_I->prev_ptr) {
+			p_I->prev_ptr->next_ptr = p_I->next_ptr;
+		}
+
+		p_I->next_ptr->prev_ptr = p_I->prev_ptr;
+
+		_data->last->next_ptr = p_I;
+		p_I->prev_ptr = _data->last;
+		p_I->next_ptr = nullptr;
+		_data->last = p_I;
+	}
+
+	void reverse() {
+		int s = size() / 2;
+		Element *F = front();
+		Element *B = back();
+		for (int i = 0; i < s; i++) {
+			SWAP(F->value, B->value);
+			F = F->next();
+			B = B->prev();
+		}
+	}
+
+	void move_to_front(Element *p_I) {
+		ERR_FAIL_COND(p_I->data != _data);
+		if (!p_I->prev_ptr) {
+			return;
+		}
+
+		if (_data->first == p_I) {
+			_data->first = p_I->next_ptr;
+		}
+
+		if (_data->last == p_I) {
+			_data->last = p_I->prev_ptr;
+		}
+
+		p_I->prev_ptr->next_ptr = p_I->next_ptr;
+
+		if (p_I->next_ptr) {
+			p_I->next_ptr->prev_ptr = p_I->prev_ptr;
+		}
+
+		_data->first->prev_ptr = p_I;
+		p_I->next_ptr = _data->first;
+		p_I->prev_ptr = nullptr;
+		_data->first = p_I;
+	}
+
+	void move_before(Element *value, Element *where) {
+		if (value->prev_ptr) {
+			value->prev_ptr->next_ptr = value->next_ptr;
+		} else {
+			_data->first = value->next_ptr;
+		}
+		if (value->next_ptr) {
+			value->next_ptr->prev_ptr = value->prev_ptr;
+		} else {
+			_data->last = value->prev_ptr;
+		}
+
+		value->next_ptr = where;
+		if (!where) {
+			value->prev_ptr = _data->last;
+			_data->last = value;
+			return;
+		}
+
+		value->prev_ptr = where->prev_ptr;
+
+		if (where->prev_ptr) {
+			where->prev_ptr->next_ptr = value;
+		} else {
+			_data->first = value;
+		}
+
+		where->prev_ptr = value;
+	}
+
+	/**
+	 * simple insertion sort
+	 */
+
+	void sort() {
+		sort_custom<Comparator<T>>();
+	}
+
+	template <class C>
+	void sort_custom_inplace() {
+		if (size() < 2) {
+			return;
+		}
+
+		Element *from = front();
+		Element *current = from;
+		Element *to = from;
+
+		while (current) {
+			Element *next = current->next_ptr;
+
+			if (from != current) {
+				current->prev_ptr = nullptr;
+				current->next_ptr = from;
+
+				Element *find = from;
+				C less;
+				while (find && less(find->value, current->value)) {
+					current->prev_ptr = find;
+					current->next_ptr = find->next_ptr;
+					find = find->next_ptr;
+				}
+
+				if (current->prev_ptr) {
+					current->prev_ptr->next_ptr = current;
+				} else {
+					from = current;
+				}
+
+				if (current->next_ptr) {
+					current->next_ptr->prev_ptr = current;
+				} else {
+					to = current;
+				}
+			} else {
+				current->prev_ptr = nullptr;
+				current->next_ptr = nullptr;
+			}
+
+			current = next;
+		}
+		_data->first = from;
+		_data->last = to;
+	}
+
+	template <class C>
+	struct AuxiliaryComparator {
+		C compare;
+		_FORCE_INLINE_ bool operator()(const Element *a, const Element *b) const {
+			return compare(a->value, b->value);
+		}
+	};
+
+	template <class C>
+	void sort_custom() {
+		// this version uses auxiliary memory for speed.
+		// if you don't want to use auxiliary memory, use the in_place version
+
+		int s = size();
+		if (s < 2) {
+			return;
+		}
+
+		Element **aux_buffer = memnew_arr(Element *, s);
+
+		int idx = 0;
+		for (Element *E = front(); E; E = E->next_ptr) {
+			aux_buffer[idx] = E;
+			idx++;
+		}
+
+		SortArray<Element *, AuxiliaryComparator<C>> sort;
+		sort.sort(aux_buffer, s);
+
+		_data->first = aux_buffer[0];
+		aux_buffer[0]->prev_ptr = nullptr;
+		aux_buffer[0]->next_ptr = aux_buffer[1];
+
+		_data->last = aux_buffer[s - 1];
+		aux_buffer[s - 1]->prev_ptr = aux_buffer[s - 2];
+		aux_buffer[s - 1]->next_ptr = nullptr;
+
+		for (int i = 1; i < s - 1; i++) {
+			aux_buffer[i]->prev_ptr = aux_buffer[i - 1];
+			aux_buffer[i]->next_ptr = aux_buffer[i + 1];
+		}
+
+		memdelete_arr(aux_buffer);
+	}
+
+	const void *id() const {
+		return (void *)_data;
+	}
+
+	/**
+	 * copy constructor for the list
+	 */
+	List(const List &p_list) {
+		const Element *it = p_list.front();
+		while (it) {
+			push_back(it->get());
+			it = it->next();
+		}
+	}
+
+	List() {}
+
+	~List() {
+		clear();
+		if (_data) {
+			ERR_FAIL_COND(_data->size_cache);
+			memdelete_allocator<_Data, A>(_data);
+		}
+	}
+};
+
+} // namespace godot
+
+#endif // ! LIST_HPP

+ 757 - 0
include/godot_cpp/templates/map.hpp

@@ -0,0 +1,757 @@
+/*************************************************************************/
+/*  map.hpp                                                              */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* 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 MAP_HPP
+#define MAP_HPP
+
+#include <godot_cpp/core/error_macros.hpp>
+#include <godot_cpp/core/memory.hpp>
+#include <godot_cpp/templates/pair.hpp>
+
+namespace godot {
+
+// 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
+
+template <class K, class V, class C = Comparator<K>, class A = DefaultAllocator>
+class Map {
+	enum Color {
+		RED,
+		BLACK
+	};
+	struct _Data;
+
+public:
+	class Element {
+	private:
+		friend class Map<K, V, C, A>;
+		int color = RED;
+		Element *right = nullptr;
+		Element *left = nullptr;
+		Element *parent = nullptr;
+		Element *_next = nullptr;
+		Element *_prev = nullptr;
+		KeyValue<K, V> _data;
+
+	public:
+		KeyValue<K, V> &key_value() { return _data; }
+		const KeyValue<K, V> &key_value() const { return _data; }
+
+		const Element *next() const {
+			return _next;
+		}
+		Element *next() {
+			return _next;
+		}
+		const Element *prev() const {
+			return _prev;
+		}
+		Element *prev() {
+			return _prev;
+		}
+		const K &key() const {
+			return _data.key;
+		}
+		V &value() {
+			return _data.value;
+		}
+		const V &value() const {
+			return _data.value;
+		}
+		V &get() {
+			return _data.value;
+		}
+		const V &get() const {
+			return _data.value;
+		}
+		Element(const KeyValue<K, V> &p_data) :
+				_data(p_data) {}
+	};
+
+	typedef KeyValue<K, V> ValueType;
+
+	struct Iterator {
+		_FORCE_INLINE_ KeyValue<K, V> &operator*() const {
+			return E->key_value();
+		}
+		_FORCE_INLINE_ KeyValue<K, V> *operator->() const { return &E->key_value(); }
+		_FORCE_INLINE_ Iterator &operator++() {
+			E = E->next();
+			return *this;
+		}
+		_FORCE_INLINE_ Iterator &operator--() {
+			E = E->prev();
+			return *this;
+		}
+
+		_FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
+		_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
+
+		Iterator(Element *p_E) { E = p_E; }
+		Iterator() {}
+		Iterator(const Iterator &p_it) { E = p_it.E; }
+
+	private:
+		Element *E = nullptr;
+	};
+
+	struct ConstIterator {
+		_FORCE_INLINE_ const KeyValue<K, V> &operator*() const {
+			return E->key_value();
+		}
+		_FORCE_INLINE_ const KeyValue<K, V> *operator->() const { return &E->key_value(); }
+		_FORCE_INLINE_ ConstIterator &operator++() {
+			E = E->next();
+			return *this;
+		}
+		_FORCE_INLINE_ ConstIterator &operator--() {
+			E = E->prev();
+			return *this;
+		}
+
+		_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return E == b.E; }
+		_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return E != b.E; }
+
+		ConstIterator(const Element *p_E) { E = p_E; }
+		ConstIterator() {}
+		ConstIterator(const ConstIterator &p_it) { E = p_it.E; }
+
+	private:
+		const Element *E = nullptr;
+	};
+
+	_FORCE_INLINE_ Iterator begin() {
+		return Iterator(front());
+	}
+	_FORCE_INLINE_ Iterator end() {
+		return Iterator(nullptr);
+	}
+
+#if 0
+	//to use when replacing find()
+	_FORCE_INLINE_ Iterator find(const K &p_key) {
+		return Iterator(find(p_key));
+	}
+#endif
+	_FORCE_INLINE_ void remove(const Iterator &p_iter) {
+		return erase(p_iter.E);
+	}
+
+	_FORCE_INLINE_ ConstIterator begin() const {
+		return ConstIterator(front());
+	}
+	_FORCE_INLINE_ ConstIterator end() const {
+		return ConstIterator(nullptr);
+	}
+
+#if 0
+	//to use when replacing find()
+	_FORCE_INLINE_ ConstIterator find(const K &p_key) const {
+		return ConstIterator(find(p_key));
+	}
+#endif
+private:
+	struct _Data {
+		Element *_root = nullptr;
+		Element *_nil;
+		int size_cache = 0;
+
+		_FORCE_INLINE_ _Data() {
+#ifdef GLOBALNIL_DISABLED
+			_nil = memnew_allocator(Element, A);
+			_nil->parent = _nil->left = _nil->right = _nil;
+			_nil->color = BLACK;
+#else
+			_nil = (Element *)&_GlobalNilClass::_nil;
+#endif
+		}
+
+		void _create_root() {
+			_root = memnew_allocator(Element(KeyValue<K, V>(K(), V())), A);
+			_root->parent = _root->left = _root->right = _nil;
+			_root->color = BLACK;
+		}
+
+		void _free_root() {
+			if (_root) {
+				memdelete_allocator<Element, A>(_root);
+				_root = nullptr;
+			}
+		}
+
+		~_Data() {
+			_free_root();
+
+#ifdef GLOBALNIL_DISABLED
+			memdelete_allocator<Element, A>(_nil);
+#endif
+		}
+	};
+
+	_Data _data;
+
+	inline void _set_color(Element *p_node, int p_color) {
+		ERR_FAIL_COND(p_node == _data._nil && p_color == RED);
+		p_node->color = p_color;
+	}
+
+	inline void _rotate_left(Element *p_node) {
+		Element *r = p_node->right;
+		p_node->right = r->left;
+		if (r->left != _data._nil) {
+			r->left->parent = p_node;
+		}
+		r->parent = p_node->parent;
+		if (p_node == p_node->parent->left) {
+			p_node->parent->left = r;
+		} else {
+			p_node->parent->right = r;
+		}
+
+		r->left = p_node;
+		p_node->parent = r;
+	}
+
+	inline void _rotate_right(Element *p_node) {
+		Element *l = p_node->left;
+		p_node->left = l->right;
+		if (l->right != _data._nil) {
+			l->right->parent = p_node;
+		}
+		l->parent = p_node->parent;
+		if (p_node == p_node->parent->right) {
+			p_node->parent->right = l;
+		} else {
+			p_node->parent->left = l;
+		}
+
+		l->right = p_node;
+		p_node->parent = l;
+	}
+
+	inline Element *_successor(Element *p_node) const {
+		Element *node = p_node;
+
+		if (node->right != _data._nil) {
+			node = node->right;
+			while (node->left != _data._nil) { /* returns the minimum of the right subtree of node */
+				node = node->left;
+			}
+			return node;
+		} else {
+			while (node == node->parent->right) {
+				node = node->parent;
+			}
+
+			if (node->parent == _data._root) {
+				return nullptr; // No successor, as p_node = last node
+			}
+			return node->parent;
+		}
+	}
+
+	inline Element *_predecessor(Element *p_node) const {
+		Element *node = p_node;
+
+		if (node->left != _data._nil) {
+			node = node->left;
+			while (node->right != _data._nil) { /* returns the minimum of the left subtree of node */
+				node = node->right;
+			}
+			return node;
+		} else {
+			while (node == node->parent->left) {
+				node = node->parent;
+			}
+
+			if (node == _data._root) {
+				return nullptr; // No predecessor, as p_node = first node
+			}
+			return node->parent;
+		}
+	}
+
+	Element *_find(const K &p_key) const {
+		Element *node = _data._root->left;
+		C less;
+
+		while (node != _data._nil) {
+			if (less(p_key, node->_data.key)) {
+				node = node->left;
+			} else if (less(node->_data.key, p_key)) {
+				node = node->right;
+			} else {
+				return node; // found
+			}
+		}
+
+		return nullptr;
+	}
+
+	Element *_find_closest(const K &p_key) const {
+		Element *node = _data._root->left;
+		Element *prev = nullptr;
+		C less;
+
+		while (node != _data._nil) {
+			prev = node;
+
+			if (less(p_key, node->_data.key)) {
+				node = node->left;
+			} else if (less(node->_data.key, p_key)) {
+				node = node->right;
+			} else {
+				return node; // found
+			}
+		}
+
+		if (prev == nullptr) {
+			return nullptr; // tree empty
+		}
+
+		if (less(p_key, prev->_data.key)) {
+			prev = prev->_prev;
+		}
+
+		return prev;
+	}
+
+	void _insert_rb_fix(Element *p_new_node) {
+		Element *node = p_new_node;
+		Element *nparent = node->parent;
+		Element *ngrand_parent;
+
+		while (nparent->color == RED) {
+			ngrand_parent = nparent->parent;
+
+			if (nparent == ngrand_parent->left) {
+				if (ngrand_parent->right->color == RED) {
+					_set_color(nparent, BLACK);
+					_set_color(ngrand_parent->right, BLACK);
+					_set_color(ngrand_parent, RED);
+					node = ngrand_parent;
+					nparent = node->parent;
+				} else {
+					if (node == nparent->right) {
+						_rotate_left(nparent);
+						node = nparent;
+						nparent = node->parent;
+					}
+					_set_color(nparent, BLACK);
+					_set_color(ngrand_parent, RED);
+					_rotate_right(ngrand_parent);
+				}
+			} else {
+				if (ngrand_parent->left->color == RED) {
+					_set_color(nparent, BLACK);
+					_set_color(ngrand_parent->left, BLACK);
+					_set_color(ngrand_parent, RED);
+					node = ngrand_parent;
+					nparent = node->parent;
+				} else {
+					if (node == nparent->left) {
+						_rotate_right(nparent);
+						node = nparent;
+						nparent = node->parent;
+					}
+					_set_color(nparent, BLACK);
+					_set_color(ngrand_parent, RED);
+					_rotate_left(ngrand_parent);
+				}
+			}
+		}
+
+		_set_color(_data._root->left, BLACK);
+	}
+
+	Element *_insert(const K &p_key, const V &p_value) {
+		Element *new_parent = _data._root;
+		Element *node = _data._root->left;
+		C less;
+
+		while (node != _data._nil) {
+			new_parent = node;
+
+			if (less(p_key, node->_data.key)) {
+				node = node->left;
+			} else if (less(node->_data.key, p_key)) {
+				node = node->right;
+			} else {
+				node->_data.value = p_value;
+				return node; // Return existing node with new value
+			}
+		}
+
+		typedef KeyValue<K, V> KV;
+		Element *new_node = memnew_allocator(Element(KV(p_key, p_value)), A);
+		new_node->parent = new_parent;
+		new_node->right = _data._nil;
+		new_node->left = _data._nil;
+
+		// new_node->data=_data;
+
+		if (new_parent == _data._root || less(p_key, new_parent->_data.key)) {
+			new_parent->left = new_node;
+		} else {
+			new_parent->right = new_node;
+		}
+
+		new_node->_next = _successor(new_node);
+		new_node->_prev = _predecessor(new_node);
+		if (new_node->_next) {
+			new_node->_next->_prev = new_node;
+		}
+		if (new_node->_prev) {
+			new_node->_prev->_next = new_node;
+		}
+
+		_data.size_cache++;
+		_insert_rb_fix(new_node);
+		return new_node;
+	}
+
+	void _erase_fix_rb(Element *p_node) {
+		Element *root = _data._root->left;
+		Element *node = _data._nil;
+		Element *sibling = p_node;
+		Element *parent = sibling->parent;
+
+		while (node != root) { // If red node found, will exit at a break
+			if (sibling->color == RED) {
+				_set_color(sibling, BLACK);
+				_set_color(parent, RED);
+				if (sibling == parent->right) {
+					sibling = sibling->left;
+					_rotate_left(parent);
+				} else {
+					sibling = sibling->right;
+					_rotate_right(parent);
+				}
+			}
+			if ((sibling->left->color == BLACK) && (sibling->right->color == BLACK)) {
+				_set_color(sibling, RED);
+				if (parent->color == RED) {
+					_set_color(parent, BLACK);
+					break;
+				} else { // loop: haven't found any red nodes yet
+					node = parent;
+					parent = node->parent;
+					sibling = (node == parent->left) ? parent->right : parent->left;
+				}
+			} else {
+				if (sibling == parent->right) {
+					if (sibling->right->color == BLACK) {
+						_set_color(sibling->left, BLACK);
+						_set_color(sibling, RED);
+						_rotate_right(sibling);
+						sibling = sibling->parent;
+					}
+					_set_color(sibling, parent->color);
+					_set_color(parent, BLACK);
+					_set_color(sibling->right, BLACK);
+					_rotate_left(parent);
+					break;
+				} else {
+					if (sibling->left->color == BLACK) {
+						_set_color(sibling->right, BLACK);
+						_set_color(sibling, RED);
+						_rotate_left(sibling);
+						sibling = sibling->parent;
+					}
+
+					_set_color(sibling, parent->color);
+					_set_color(parent, BLACK);
+					_set_color(sibling->left, BLACK);
+					_rotate_right(parent);
+					break;
+				}
+			}
+		}
+
+		ERR_FAIL_COND(_data._nil->color != BLACK);
+	}
+
+	void _erase(Element *p_node) {
+		Element *rp = ((p_node->left == _data._nil) || (p_node->right == _data._nil)) ? p_node : p_node->_next;
+		Element *node = (rp->left == _data._nil) ? rp->right : rp->left;
+
+		Element *sibling;
+		if (rp == rp->parent->left) {
+			rp->parent->left = node;
+			sibling = rp->parent->right;
+		} else {
+			rp->parent->right = node;
+			sibling = rp->parent->left;
+		}
+
+		if (node->color == RED) {
+			node->parent = rp->parent;
+			_set_color(node, BLACK);
+		} else if (rp->color == BLACK && rp->parent != _data._root) {
+			_erase_fix_rb(sibling);
+		}
+
+		if (rp != p_node) {
+			ERR_FAIL_COND(rp == _data._nil);
+
+			rp->left = p_node->left;
+			rp->right = p_node->right;
+			rp->parent = p_node->parent;
+			rp->color = p_node->color;
+			if (p_node->left != _data._nil) {
+				p_node->left->parent = rp;
+			}
+			if (p_node->right != _data._nil) {
+				p_node->right->parent = rp;
+			}
+
+			if (p_node == p_node->parent->left) {
+				p_node->parent->left = rp;
+			} else {
+				p_node->parent->right = rp;
+			}
+		}
+
+		if (p_node->_next) {
+			p_node->_next->_prev = p_node->_prev;
+		}
+		if (p_node->_prev) {
+			p_node->_prev->_next = p_node->_next;
+		}
+
+		memdelete_allocator<Element, A>(p_node);
+		_data.size_cache--;
+		ERR_FAIL_COND(_data._nil->color == RED);
+	}
+
+	void _calculate_depth(Element *p_element, int &max_d, int d) const {
+		if (p_element == _data._nil) {
+			return;
+		}
+
+		_calculate_depth(p_element->left, max_d, d + 1);
+		_calculate_depth(p_element->right, max_d, d + 1);
+
+		if (d > max_d) {
+			max_d = d;
+		}
+	}
+
+	void _cleanup_tree(Element *p_element) {
+		if (p_element == _data._nil) {
+			return;
+		}
+
+		_cleanup_tree(p_element->left);
+		_cleanup_tree(p_element->right);
+		memdelete_allocator<Element, A>(p_element);
+	}
+
+	void _copy_from(const Map &p_map) {
+		clear();
+		// not the fastest way, but safeset to write.
+		for (Element *I = p_map.front(); I; I = I->next()) {
+			insert(I->key(), I->value());
+		}
+	}
+
+public:
+	const Element *find(const K &p_key) const {
+		if (!_data._root) {
+			return nullptr;
+		}
+
+		const Element *res = _find(p_key);
+		return res;
+	}
+
+	Element *find(const K &p_key) {
+		if (!_data._root) {
+			return nullptr;
+		}
+
+		Element *res = _find(p_key);
+		return res;
+	}
+
+	const Element *find_closest(const K &p_key) const {
+		if (!_data._root) {
+			return nullptr;
+		}
+
+		const Element *res = _find_closest(p_key);
+		return res;
+	}
+
+	Element *find_closest(const K &p_key) {
+		if (!_data._root) {
+			return nullptr;
+		}
+
+		Element *res = _find_closest(p_key);
+		return res;
+	}
+
+	bool has(const K &p_key) const {
+		return find(p_key) != nullptr;
+	}
+
+	Element *insert(const K &p_key, const V &p_value) {
+		if (!_data._root) {
+			_data._create_root();
+		}
+		return _insert(p_key, p_value);
+	}
+
+	void erase(Element *p_element) {
+		if (!_data._root || !p_element) {
+			return;
+		}
+
+		_erase(p_element);
+		if (_data.size_cache == 0 && _data._root) {
+			_data._free_root();
+		}
+	}
+
+	bool erase(const K &p_key) {
+		if (!_data._root) {
+			return false;
+		}
+
+		Element *e = find(p_key);
+		if (!e) {
+			return false;
+		}
+
+		_erase(e);
+		if (_data.size_cache == 0 && _data._root) {
+			_data._free_root();
+		}
+		return true;
+	}
+
+	const V &operator[](const K &p_key) const {
+		CRASH_COND(!_data._root);
+		const Element *e = find(p_key);
+		CRASH_COND(!e);
+		return e->_data.value;
+	}
+
+	V &operator[](const K &p_key) {
+		if (!_data._root) {
+			_data._create_root();
+		}
+
+		Element *e = find(p_key);
+		if (!e) {
+			e = insert(p_key, V());
+		}
+
+		return e->_data.value;
+	}
+
+	Element *front() const {
+		if (!_data._root) {
+			return nullptr;
+		}
+
+		Element *e = _data._root->left;
+		if (e == _data._nil) {
+			return nullptr;
+		}
+
+		while (e->left != _data._nil) {
+			e = e->left;
+		}
+
+		return e;
+	}
+
+	Element *back() const {
+		if (!_data._root) {
+			return nullptr;
+		}
+
+		Element *e = _data._root->left;
+		if (e == _data._nil) {
+			return nullptr;
+		}
+
+		while (e->right != _data._nil) {
+			e = e->right;
+		}
+
+		return e;
+	}
+
+	inline bool is_empty() const { return _data.size_cache == 0; }
+	inline int size() const { return _data.size_cache; }
+
+	int calculate_depth() const {
+		// used for debug mostly
+		if (!_data._root) {
+			return 0;
+		}
+
+		int max_d = 0;
+		_calculate_depth(_data._root->left, max_d, 0);
+		return max_d;
+	}
+
+	void clear() {
+		if (!_data._root) {
+			return;
+		}
+
+		_cleanup_tree(_data._root->left);
+		_data._root->left = _data._nil;
+		_data.size_cache = 0;
+		_data._free_root();
+	}
+
+	void operator=(const Map &p_map) {
+		_copy_from(p_map);
+	}
+
+	Map(const Map &p_map) {
+		_copy_from(p_map);
+	}
+
+	_FORCE_INLINE_ Map() {}
+
+	~Map() {
+		clear();
+	}
+};
+
+} // namespace godot
+
+#endif // ! MAP_HPP

+ 107 - 0
include/godot_cpp/templates/pair.hpp

@@ -0,0 +1,107 @@
+/*************************************************************************/
+/*  pair.hpp                                                             */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* 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 PAIR_HPP
+#define PAIR_HPP
+
+namespace godot {
+
+template <class F, class S>
+struct Pair {
+	F first;
+	S second;
+
+	Pair() :
+			first(),
+			second() {
+	}
+
+	Pair(F p_first, const S &p_second) :
+			first(p_first),
+			second(p_second) {
+	}
+};
+
+template <class F, class S>
+bool operator==(const Pair<F, S> &pair, const Pair<F, S> &other) {
+	return (pair.first == other.first) && (pair.second == other.second);
+}
+
+template <class F, class S>
+bool operator!=(const Pair<F, S> &pair, const Pair<F, S> &other) {
+	return (pair.first != other.first) || (pair.second != other.second);
+}
+
+template <class F, class S>
+struct PairSort {
+	bool operator()(const Pair<F, S> &A, const Pair<F, S> &B) const {
+		if (A.first != B.first) {
+			return A.first < B.first;
+		}
+		return A.second < B.second;
+	}
+};
+
+template <class K, class V>
+struct KeyValue {
+	const K key;
+	V value;
+
+	void operator=(const KeyValue &p_kv) = delete;
+	_FORCE_INLINE_ KeyValue(const KeyValue &p_kv) :
+			key(p_kv.key),
+			value(p_kv.value) {
+	}
+	_FORCE_INLINE_ KeyValue(const K &p_key, const V &p_value) :
+			key(p_key),
+			value(p_value) {
+	}
+};
+
+template <class K, class V>
+bool operator==(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) {
+	return (pair.key == other.key) && (pair.value == other.value);
+}
+
+template <class K, class V>
+bool operator!=(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) {
+	return (pair.key != other.key) || (pair.value != other.value);
+}
+
+template <class K, class V>
+struct KeyValueSort {
+	bool operator()(const KeyValue<K, V> &A, const KeyValue<K, V> &B) const {
+		return A.key < B.key;
+	}
+};
+
+} // namespace godot
+
+#endif // ! PAIR_HPP

+ 465 - 0
include/godot_cpp/templates/rid_owner.hpp

@@ -0,0 +1,465 @@
+/*************************************************************************/
+/*  rid_owner.hpp                                                        */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* 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 RID_OWNER_HPP
+#define RID_OWNER_HPP
+
+#include <godot_cpp/core/memory.hpp>
+#include <godot_cpp/godot.hpp>
+#include <godot_cpp/templates/list.hpp>
+#include <godot_cpp/templates/spin_lock.hpp>
+#include <godot_cpp/variant/utility_functions.hpp>
+
+#include <stdio.h>
+#include <typeinfo>
+
+namespace godot {
+
+template <class T, bool THREAD_SAFE = false>
+class RID_Alloc {
+	T **chunks = nullptr;
+	uint32_t **free_list_chunks = nullptr;
+	uint32_t **validator_chunks = nullptr;
+
+	uint32_t elements_in_chunk;
+	uint32_t max_alloc = 0;
+	uint32_t alloc_count = 0;
+
+	const char *description = nullptr;
+
+	SpinLock spin_lock;
+
+	_FORCE_INLINE_ RID _allocate_rid() {
+		if (THREAD_SAFE) {
+			spin_lock.lock();
+		}
+
+		if (alloc_count == max_alloc) {
+			// allocate a new chunk
+			uint32_t chunk_count = alloc_count == 0 ? 0 : (max_alloc / elements_in_chunk);
+
+			// grow chunks
+			chunks = (T **)memrealloc(chunks, sizeof(T *) * (chunk_count + 1));
+			chunks[chunk_count] = (T *)memalloc(sizeof(T) * elements_in_chunk); // but don't initialize
+
+			// grow validators
+			validator_chunks = (uint32_t **)memrealloc(validator_chunks, sizeof(uint32_t *) * (chunk_count + 1));
+			validator_chunks[chunk_count] = (uint32_t *)memalloc(sizeof(uint32_t) * elements_in_chunk);
+			// grow free lists
+			free_list_chunks = (uint32_t **)memrealloc(free_list_chunks, sizeof(uint32_t *) * (chunk_count + 1));
+			free_list_chunks[chunk_count] = (uint32_t *)memalloc(sizeof(uint32_t) * elements_in_chunk);
+
+			// initialize
+			for (uint32_t i = 0; i < elements_in_chunk; i++) {
+				// Don't initialize chunk.
+				validator_chunks[chunk_count][i] = 0xFFFFFFFF;
+				free_list_chunks[chunk_count][i] = alloc_count + i;
+			}
+
+			max_alloc += elements_in_chunk;
+		}
+
+		uint32_t free_index = free_list_chunks[alloc_count / elements_in_chunk][alloc_count % elements_in_chunk];
+
+		uint32_t free_chunk = free_index / elements_in_chunk;
+		uint32_t free_element = free_index % elements_in_chunk;
+
+		uint32_t validator = (uint32_t)(UtilityFunctions::rid_allocate_id() & 0x7FFFFFFF);
+		uint64_t id = validator;
+		id <<= 32;
+		id |= free_index;
+
+		validator_chunks[free_chunk][free_element] = validator;
+
+		validator_chunks[free_chunk][free_element] |= 0x80000000; // mark uninitialized bit
+
+		alloc_count++;
+
+		if (THREAD_SAFE) {
+			spin_lock.unlock();
+		}
+
+		return UtilityFunctions::rid_from_int64(id);
+	}
+
+public:
+	RID make_rid() {
+		RID rid = _allocate_rid();
+		initialize_rid(rid);
+		return rid;
+	}
+	RID make_rid(const T &p_value) {
+		RID rid = _allocate_rid();
+		initialize_rid(rid, p_value);
+		return rid;
+	}
+
+	// allocate but don't initialize, use initialize_rid afterwards
+	RID allocate_rid() {
+		return _allocate_rid();
+	}
+
+	_FORCE_INLINE_ T *get_or_null(const RID &p_rid, bool p_initialize = false) {
+		if (p_rid == RID()) {
+			return nullptr;
+		}
+		if (THREAD_SAFE) {
+			spin_lock.lock();
+		}
+
+		uint64_t id = p_rid.get_id();
+		uint32_t idx = uint32_t(id & 0xFFFFFFFF);
+		if (unlikely(idx >= max_alloc)) {
+			if (THREAD_SAFE) {
+				spin_lock.unlock();
+			}
+			return nullptr;
+		}
+
+		uint32_t idx_chunk = idx / elements_in_chunk;
+		uint32_t idx_element = idx % elements_in_chunk;
+
+		uint32_t validator = uint32_t(id >> 32);
+
+		if (unlikely(p_initialize)) {
+			if (unlikely(!(validator_chunks[idx_chunk][idx_element] & 0x80000000))) {
+				if (THREAD_SAFE) {
+					spin_lock.unlock();
+				}
+				ERR_FAIL_V_MSG(nullptr, "Initializing already initialized RID");
+			}
+
+			if (unlikely((validator_chunks[idx_chunk][idx_element] & 0x7FFFFFFF) != validator)) {
+				if (THREAD_SAFE) {
+					spin_lock.unlock();
+				}
+				ERR_FAIL_V_MSG(nullptr, "Attempting to initialize the wrong RID");
+				return nullptr;
+			}
+
+			validator_chunks[idx_chunk][idx_element] &= 0x7FFFFFFF; // initialized
+
+		} else if (unlikely(validator_chunks[idx_chunk][idx_element] != validator)) {
+			if (THREAD_SAFE) {
+				spin_lock.unlock();
+			}
+			if ((validator_chunks[idx_chunk][idx_element] & 0x80000000) && validator_chunks[idx_chunk][idx_element] != 0xFFFFFFFF) {
+				ERR_FAIL_V_MSG(nullptr, "Attempting to use an uninitialized RID");
+			}
+			return nullptr;
+		}
+
+		T *ptr = &chunks[idx_chunk][idx_element];
+
+		if (THREAD_SAFE) {
+			spin_lock.unlock();
+		}
+
+		return ptr;
+	}
+	void initialize_rid(RID p_rid) {
+		T *mem = get_or_null(p_rid, true);
+		ERR_FAIL_COND(!mem);
+		memnew_placement(mem, T);
+	}
+	void initialize_rid(RID p_rid, const T &p_value) {
+		T *mem = get_or_null(p_rid, true);
+		ERR_FAIL_COND(!mem);
+		memnew_placement(mem, T(p_value));
+	}
+
+	_FORCE_INLINE_ bool owns(const RID &p_rid) {
+		if (THREAD_SAFE) {
+			spin_lock.lock();
+		}
+
+		uint64_t id = p_rid.get_id();
+		uint32_t idx = uint32_t(id & 0xFFFFFFFF);
+		if (unlikely(idx >= max_alloc)) {
+			if (THREAD_SAFE) {
+				spin_lock.unlock();
+			}
+			return false;
+		}
+
+		uint32_t idx_chunk = idx / elements_in_chunk;
+		uint32_t idx_element = idx % elements_in_chunk;
+
+		uint32_t validator = uint32_t(id >> 32);
+
+		bool owned = (validator_chunks[idx_chunk][idx_element] & 0x7FFFFFFF) == validator;
+
+		if (THREAD_SAFE) {
+			spin_lock.unlock();
+		}
+
+		return owned;
+	}
+
+	_FORCE_INLINE_ void free(const RID &p_rid) {
+		if (THREAD_SAFE) {
+			spin_lock.lock();
+		}
+
+		uint64_t id = p_rid.get_id();
+		uint32_t idx = uint32_t(id & 0xFFFFFFFF);
+		if (unlikely(idx >= max_alloc)) {
+			if (THREAD_SAFE) {
+				spin_lock.unlock();
+			}
+			ERR_FAIL();
+		}
+
+		uint32_t idx_chunk = idx / elements_in_chunk;
+		uint32_t idx_element = idx % elements_in_chunk;
+
+		uint32_t validator = uint32_t(id >> 32);
+		if (unlikely(validator_chunks[idx_chunk][idx_element] & 0x80000000)) {
+			if (THREAD_SAFE) {
+				spin_lock.unlock();
+			}
+			ERR_FAIL_MSG("Attempted to free an uninitialized or invalid RID");
+		} else if (unlikely(validator_chunks[idx_chunk][idx_element] != validator)) {
+			if (THREAD_SAFE) {
+				spin_lock.unlock();
+			}
+			ERR_FAIL();
+		}
+
+		chunks[idx_chunk][idx_element].~T();
+		validator_chunks[idx_chunk][idx_element] = 0xFFFFFFFF; // go invalid
+
+		alloc_count--;
+		free_list_chunks[alloc_count / elements_in_chunk][alloc_count % elements_in_chunk] = idx;
+
+		if (THREAD_SAFE) {
+			spin_lock.unlock();
+		}
+	}
+
+	_FORCE_INLINE_ uint32_t get_rid_count() const {
+		return alloc_count;
+	}
+
+	void get_owned_list(List<RID> *p_owned) {
+		if (THREAD_SAFE) {
+			spin_lock.lock();
+		}
+		for (size_t i = 0; i < max_alloc; i++) {
+			uint64_t validator = validator_chunks[i / elements_in_chunk][i % elements_in_chunk];
+			if (validator != 0xFFFFFFFF) {
+				p_owned->push_back(UtilityFunctions::rid_from_int64((validator << 32) | i));
+			}
+		}
+		if (THREAD_SAFE) {
+			spin_lock.unlock();
+		}
+	}
+
+	// used for fast iteration in the elements or RIDs
+	void fill_owned_buffer(RID *p_rid_buffer) {
+		if (THREAD_SAFE) {
+			spin_lock.lock();
+		}
+		uint32_t idx = 0;
+		for (size_t i = 0; i < max_alloc; i++) {
+			uint64_t validator = validator_chunks[i / elements_in_chunk][i % elements_in_chunk];
+			if (validator != 0xFFFFFFFF) {
+				p_rid_buffer[idx] = UtilityFunctions::rid_from_int64((validator << 32) | i);
+				idx++;
+			}
+		}
+		if (THREAD_SAFE) {
+			spin_lock.unlock();
+		}
+	}
+
+	void set_description(const char *p_descrption) {
+		description = p_descrption;
+	}
+
+	RID_Alloc(uint32_t p_target_chunk_byte_size = 65536) {
+		elements_in_chunk = sizeof(T) > p_target_chunk_byte_size ? 1 : (p_target_chunk_byte_size / sizeof(T));
+	}
+
+	~RID_Alloc() {
+		if (alloc_count) {
+			if (description) {
+				printf("ERROR: %d  RID allocations of type '%s' were leaked at exit.", alloc_count, description);
+			} else {
+#ifdef NO_SAFE_CAST
+				printf("ERROR: %d RID allocations of type 'unknown' were leaked at exit.", alloc_count);
+#else
+				printf("ERROR: %d RID allocations of type '%s' were leaked at exit.", alloc_count, typeid(T).name());
+#endif
+			}
+
+			for (size_t i = 0; i < max_alloc; i++) {
+				uint64_t validator = validator_chunks[i / elements_in_chunk][i % elements_in_chunk];
+				if (validator & 0x80000000) {
+					continue; // uninitialized
+				}
+				if (validator != 0xFFFFFFFF) {
+					chunks[i / elements_in_chunk][i % elements_in_chunk].~T();
+				}
+			}
+		}
+
+		uint32_t chunk_count = max_alloc / elements_in_chunk;
+		for (uint32_t i = 0; i < chunk_count; i++) {
+			memfree(chunks[i]);
+			memfree(validator_chunks[i]);
+			memfree(free_list_chunks[i]);
+		}
+
+		if (chunks) {
+			memfree(chunks);
+			memfree(free_list_chunks);
+			memfree(validator_chunks);
+		}
+	}
+};
+
+template <class T, bool THREAD_SAFE = false>
+class RID_PtrOwner {
+	RID_Alloc<T *, THREAD_SAFE> alloc;
+
+public:
+	_FORCE_INLINE_ RID make_rid(T *p_ptr) {
+		return alloc.make_rid(p_ptr);
+	}
+
+	_FORCE_INLINE_ RID allocate_rid() {
+		return alloc.allocate_rid();
+	}
+
+	_FORCE_INLINE_ void initialize_rid(RID p_rid, T *p_ptr) {
+		alloc.initialize_rid(p_rid, p_ptr);
+	}
+
+	_FORCE_INLINE_ T *get_or_null(const RID &p_rid) {
+		T **ptr = alloc.get_or_null(p_rid);
+		if (unlikely(!ptr)) {
+			return nullptr;
+		}
+		return *ptr;
+	}
+
+	_FORCE_INLINE_ void replace(const RID &p_rid, T *p_new_ptr) {
+		T **ptr = alloc.get_or_null(p_rid);
+		ERR_FAIL_COND(!ptr);
+		*ptr = p_new_ptr;
+	}
+
+	_FORCE_INLINE_ bool owns(const RID &p_rid) {
+		return alloc.owns(p_rid);
+	}
+
+	_FORCE_INLINE_ void free(const RID &p_rid) {
+		alloc.free(p_rid);
+	}
+
+	_FORCE_INLINE_ uint32_t get_rid_count() const {
+		return alloc.get_rid_count();
+	}
+
+	_FORCE_INLINE_ void get_owned_list(List<RID> *p_owned) {
+		return alloc.get_owned_list(p_owned);
+	}
+
+	void fill_owned_buffer(RID *p_rid_buffer) {
+		alloc.fill_owned_buffer(p_rid_buffer);
+	}
+
+	void set_description(const char *p_descrption) {
+		alloc.set_description(p_descrption);
+	}
+
+	RID_PtrOwner(uint32_t p_target_chunk_byte_size = 65536) :
+			alloc(p_target_chunk_byte_size) {}
+};
+
+template <class T, bool THREAD_SAFE = false>
+class RID_Owner {
+	RID_Alloc<T, THREAD_SAFE> alloc;
+
+public:
+	_FORCE_INLINE_ RID make_rid() {
+		return alloc.make_rid();
+	}
+	_FORCE_INLINE_ RID make_rid(const T &p_ptr) {
+		return alloc.make_rid(p_ptr);
+	}
+
+	_FORCE_INLINE_ RID allocate_rid() {
+		return alloc.allocate_rid();
+	}
+
+	_FORCE_INLINE_ void initialize_rid(RID p_rid) {
+		alloc.initialize_rid(p_rid);
+	}
+
+	_FORCE_INLINE_ void initialize_rid(RID p_rid, const T &p_ptr) {
+		alloc.initialize_rid(p_rid, p_ptr);
+	}
+
+	_FORCE_INLINE_ T *get_or_null(const RID &p_rid) {
+		return alloc.get_or_null(p_rid);
+	}
+
+	_FORCE_INLINE_ bool owns(const RID &p_rid) {
+		return alloc.owns(p_rid);
+	}
+
+	_FORCE_INLINE_ void free(const RID &p_rid) {
+		alloc.free(p_rid);
+	}
+
+	_FORCE_INLINE_ uint32_t get_rid_count() const {
+		return alloc.get_rid_count();
+	}
+
+	_FORCE_INLINE_ void get_owned_list(List<RID> *p_owned) {
+		return alloc.get_owned_list(p_owned);
+	}
+	void fill_owned_buffer(RID *p_rid_buffer) {
+		alloc.fill_owned_buffer(p_rid_buffer);
+	}
+
+	void set_description(const char *p_descrption) {
+		alloc.set_description(p_descrption);
+	}
+	RID_Owner(uint32_t p_target_chunk_byte_size = 65536) :
+			alloc(p_target_chunk_byte_size) {}
+};
+
+} // namespace godot
+
+#endif // ! RID_OWNER_HPP

+ 326 - 0
include/godot_cpp/templates/safe_refcount.hpp

@@ -0,0 +1,326 @@
+/*************************************************************************/
+/*  safe_refcount.hpp                                                    */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* 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 SAFE_REFCOUNT_HPP
+#define SAFE_REFCOUNT_HPP
+
+#if !defined(NO_THREADS)
+
+#include <atomic>
+#include <type_traits>
+
+namespace godot {
+
+// Design goals for these classes:
+// - No automatic conversions or arithmetic operators,
+//   to keep explicit the use of atomics everywhere.
+// - Using acquire-release semantics, even to set the first value.
+//   The first value may be set relaxedly in many cases, but adding the distinction
+//   between relaxed and unrelaxed operation to the interface would make it needlessly
+//   flexible. There's negligible waste in having release semantics for the initial
+//   value and, as an important benefit, you can be sure the value is properly synchronized
+//   even with threads that are already running.
+
+template <class T>
+class SafeNumeric {
+	std::atomic<T> value;
+
+	static_assert(std::atomic<T>::is_always_lock_free);
+
+public:
+	_ALWAYS_INLINE_ void set(T p_value) {
+		value.store(p_value, std::memory_order_release);
+	}
+
+	_ALWAYS_INLINE_ T get() const {
+		return value.load(std::memory_order_acquire);
+	}
+
+	_ALWAYS_INLINE_ T increment() {
+		return value.fetch_add(1, std::memory_order_acq_rel) + 1;
+	}
+
+	// Returns the original value instead of the new one
+	_ALWAYS_INLINE_ T postincrement() {
+		return value.fetch_add(1, std::memory_order_acq_rel);
+	}
+
+	_ALWAYS_INLINE_ T decrement() {
+		return value.fetch_sub(1, std::memory_order_acq_rel) - 1;
+	}
+
+	// Returns the original value instead of the new one
+	_ALWAYS_INLINE_ T postdecrement() {
+		return value.fetch_sub(1, std::memory_order_acq_rel);
+	}
+
+	_ALWAYS_INLINE_ T add(T p_value) {
+		return value.fetch_add(p_value, std::memory_order_acq_rel) + p_value;
+	}
+
+	// Returns the original value instead of the new one
+	_ALWAYS_INLINE_ T postadd(T p_value) {
+		return value.fetch_add(p_value, std::memory_order_acq_rel);
+	}
+
+	_ALWAYS_INLINE_ T sub(T p_value) {
+		return value.fetch_sub(p_value, std::memory_order_acq_rel) - p_value;
+	}
+
+	// Returns the original value instead of the new one
+	_ALWAYS_INLINE_ T postsub(T p_value) {
+		return value.fetch_sub(p_value, std::memory_order_acq_rel);
+	}
+
+	_ALWAYS_INLINE_ T exchange_if_greater(T p_value) {
+		while (true) {
+			T tmp = value.load(std::memory_order_acquire);
+			if (tmp >= p_value) {
+				return tmp; // already greater, or equal
+			}
+			if (value.compare_exchange_weak(tmp, p_value, std::memory_order_release)) {
+				return p_value;
+			}
+		}
+	}
+
+	_ALWAYS_INLINE_ T conditional_increment() {
+		while (true) {
+			T c = value.load(std::memory_order_acquire);
+			if (c == 0) {
+				return 0;
+			}
+			if (value.compare_exchange_weak(c, c + 1, std::memory_order_release)) {
+				return c + 1;
+			}
+		}
+	}
+
+	_ALWAYS_INLINE_ explicit SafeNumeric<T>(T p_value = static_cast<T>(0)) {
+		set(p_value);
+	}
+};
+
+class SafeFlag {
+	std::atomic_bool flag;
+
+	static_assert(std::atomic_bool::is_always_lock_free);
+
+public:
+	_ALWAYS_INLINE_ bool is_set() const {
+		return flag.load(std::memory_order_acquire);
+	}
+
+	_ALWAYS_INLINE_ void set() {
+		flag.store(true, std::memory_order_release);
+	}
+
+	_ALWAYS_INLINE_ void clear() {
+		flag.store(false, std::memory_order_release);
+	}
+
+	_ALWAYS_INLINE_ void set_to(bool p_value) {
+		flag.store(p_value, std::memory_order_release);
+	}
+
+	_ALWAYS_INLINE_ explicit SafeFlag(bool p_value = false) {
+		set_to(p_value);
+	}
+};
+
+class SafeRefCount {
+	SafeNumeric<uint32_t> count;
+
+public:
+	_ALWAYS_INLINE_ bool ref() { // true on success
+		return count.conditional_increment() != 0;
+	}
+
+	_ALWAYS_INLINE_ uint32_t refval() { // none-zero on success
+		return count.conditional_increment();
+	}
+
+	_ALWAYS_INLINE_ bool unref() { // true if must be disposed of
+		return count.decrement() == 0;
+	}
+
+	_ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of
+		return count.decrement();
+	}
+
+	_ALWAYS_INLINE_ uint32_t get() const {
+		return count.get();
+	}
+
+	_ALWAYS_INLINE_ void init(uint32_t p_value = 1) {
+		count.set(p_value);
+	}
+};
+
+#else
+
+template <class T>
+class SafeNumeric {
+protected:
+	T value;
+
+public:
+	_ALWAYS_INLINE_ void set(T p_value) {
+		value = p_value;
+	}
+
+	_ALWAYS_INLINE_ T get() const {
+		return value;
+	}
+
+	_ALWAYS_INLINE_ T increment() {
+		return ++value;
+	}
+
+	_ALWAYS_INLINE_ T postincrement() {
+		return value++;
+	}
+
+	_ALWAYS_INLINE_ T decrement() {
+		return --value;
+	}
+
+	_ALWAYS_INLINE_ T postdecrement() {
+		return value--;
+	}
+
+	_ALWAYS_INLINE_ T add(T p_value) {
+		return value += p_value;
+	}
+
+	_ALWAYS_INLINE_ T postadd(T p_value) {
+		T old = value;
+		value += p_value;
+		return old;
+	}
+
+	_ALWAYS_INLINE_ T sub(T p_value) {
+		return value -= p_value;
+	}
+
+	_ALWAYS_INLINE_ T postsub(T p_value) {
+		T old = value;
+		value -= p_value;
+		return old;
+	}
+
+	_ALWAYS_INLINE_ T exchange_if_greater(T p_value) {
+		if (value < p_value) {
+			value = p_value;
+		}
+		return value;
+	}
+
+	_ALWAYS_INLINE_ T conditional_increment() {
+		if (value == 0) {
+			return 0;
+		} else {
+			return ++value;
+		}
+	}
+
+	_ALWAYS_INLINE_ explicit SafeNumeric<T>(T p_value = static_cast<T>(0)) :
+			value(p_value) {
+	}
+};
+
+class SafeFlag {
+protected:
+	bool flag;
+
+public:
+	_ALWAYS_INLINE_ bool is_set() const {
+		return flag;
+	}
+
+	_ALWAYS_INLINE_ void set() {
+		flag = true;
+	}
+
+	_ALWAYS_INLINE_ void clear() {
+		flag = false;
+	}
+
+	_ALWAYS_INLINE_ void set_to(bool p_value) {
+		flag = p_value;
+	}
+
+	_ALWAYS_INLINE_ explicit SafeFlag(bool p_value = false) :
+			flag(p_value) {}
+};
+
+class SafeRefCount {
+	uint32_t count = 0;
+
+public:
+	_ALWAYS_INLINE_ bool ref() { // true on success
+		if (count != 0) {
+			++count;
+			return true;
+		} else {
+			return false;
+		}
+	}
+
+	_ALWAYS_INLINE_ uint32_t refval() { // none-zero on success
+		if (count != 0) {
+			return ++count;
+		} else {
+			return 0;
+		}
+	}
+
+	_ALWAYS_INLINE_ bool unref() { // true if must be disposed of
+		return --count == 0;
+	}
+
+	_ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of
+		return --count;
+	}
+
+	_ALWAYS_INLINE_ uint32_t get() const {
+		return count;
+	}
+
+	_ALWAYS_INLINE_ void init(uint32_t p_value = 1) {
+		count = p_value;
+	}
+};
+
+#endif
+
+} // namespace godot
+
+#endif // ! SAFE_REFCOUNT_HPP

+ 71 - 0
include/godot_cpp/templates/search_array.hpp

@@ -0,0 +1,71 @@
+/*************************************************************************/
+/*  search_array.hpp                                                     */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* 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 SEARCH_ARRAY_HPP
+#define SEARCH_ARRAY_HPP
+
+#include <godot_cpp/templates/sort_array.hpp>
+
+namespace godot {
+
+template <class T, class Comparator = _DefaultComparator<T>>
+class SearchArray {
+public:
+	Comparator compare;
+
+	inline int bisect(const T *p_array, int p_len, const T &p_value, bool p_before) const {
+		int lo = 0;
+		int hi = p_len;
+		if (p_before) {
+			while (lo < hi) {
+				const int mid = (lo + hi) / 2;
+				if (compare(p_array[mid], p_value)) {
+					lo = mid + 1;
+				} else {
+					hi = mid;
+				}
+			}
+		} else {
+			while (lo < hi) {
+				const int mid = (lo + hi) / 2;
+				if (compare(p_value, p_array[mid])) {
+					hi = mid;
+				} else {
+					lo = mid + 1;
+				}
+			}
+		}
+		return lo;
+	}
+};
+
+} // namespace godot
+
+#endif // ! SEARCH_ARRAY_HPP

+ 707 - 0
include/godot_cpp/templates/set.hpp

@@ -0,0 +1,707 @@
+/*************************************************************************/
+/*  set.hpp                                                              */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* 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_HPP
+#define SET_HPP
+
+#include <godot_cpp/core/memory.hpp>
+
+// 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
+
+namespace godot {
+
+template <class T, class C = Comparator<T>, class A = DefaultAllocator>
+class Set {
+	enum Color {
+		RED,
+		BLACK
+	};
+	struct _Data;
+
+public:
+	class Element {
+	private:
+		friend class Set<T, C, A>;
+		int color = RED;
+		Element *right = nullptr;
+		Element *left = nullptr;
+		Element *parent = nullptr;
+		Element *_next = nullptr;
+		Element *_prev = nullptr;
+		T value;
+		//_Data *data;
+
+	public:
+		const Element *next() const {
+			return _next;
+		}
+		Element *next() {
+			return _next;
+		}
+		const Element *prev() const {
+			return _prev;
+		}
+		Element *prev() {
+			return _prev;
+		}
+		T &get() {
+			return value;
+		}
+		const T &get() const {
+			return value;
+		};
+		Element() {}
+	};
+
+	typedef T ValueType;
+
+	struct Iterator {
+		_FORCE_INLINE_ T &operator*() const {
+			return E->get();
+		}
+		_FORCE_INLINE_ T *operator->() const { return &E->get(); }
+		_FORCE_INLINE_ Iterator &operator++() {
+			E = E->next();
+			return *this;
+		}
+		_FORCE_INLINE_ Iterator &operator--() {
+			E = E->prev();
+			return *this;
+		}
+
+		_FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
+		_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
+
+		Iterator(Element *p_E) { E = p_E; }
+		Iterator() {}
+		Iterator(const Iterator &p_it) { E = p_it.E; }
+
+	private:
+		Element *E = nullptr;
+	};
+
+	struct ConstIterator {
+		_FORCE_INLINE_ const T &operator*() const {
+			return E->get();
+		}
+		_FORCE_INLINE_ const T *operator->() const { return &E->get(); }
+		_FORCE_INLINE_ ConstIterator &operator++() {
+			E = E->next();
+			return *this;
+		}
+		_FORCE_INLINE_ ConstIterator &operator--() {
+			E = E->prev();
+			return *this;
+		}
+
+		_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return E == b.E; }
+		_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return E != b.E; }
+
+		_FORCE_INLINE_ ConstIterator(const Element *p_E) { E = p_E; }
+		_FORCE_INLINE_ ConstIterator() {}
+		_FORCE_INLINE_ ConstIterator(const ConstIterator &p_it) { E = p_it.E; }
+
+	private:
+		const Element *E = nullptr;
+	};
+
+	_FORCE_INLINE_ Iterator begin() {
+		return Iterator(front());
+	}
+	_FORCE_INLINE_ Iterator end() {
+		return Iterator(nullptr);
+	}
+
+#if 0
+	//to use when replacing find()
+	_FORCE_INLINE_ Iterator find(const K &p_key) {
+		return Iterator(find(p_key));
+	}
+#endif
+
+	_FORCE_INLINE_ ConstIterator begin() const {
+		return ConstIterator(front());
+	}
+	_FORCE_INLINE_ ConstIterator end() const {
+		return ConstIterator(nullptr);
+	}
+
+#if 0
+	//to use when replacing find()
+	_FORCE_INLINE_ ConstIterator find(const K &p_key) const {
+		return ConstIterator(find(p_key));
+	}
+#endif
+private:
+	struct _Data {
+		Element *_root = nullptr;
+		Element *_nil = nullptr;
+		int size_cache = 0;
+
+		_FORCE_INLINE_ _Data() {
+#ifdef GLOBALNIL_DISABLED
+			_nil = memnew_allocator(Element, A);
+			_nil->parent = _nil->left = _nil->right = _nil;
+			_nil->color = BLACK;
+#else
+			_nil = (Element *)&_GlobalNilClass::_nil;
+#endif
+		}
+
+		void _create_root() {
+			_root = memnew_allocator(Element, A);
+			_root->parent = _root->left = _root->right = _nil;
+			_root->color = BLACK;
+		}
+
+		void _free_root() {
+			if (_root) {
+				memdelete_allocator<Element, A>(_root);
+				_root = nullptr;
+			}
+		}
+
+		~_Data() {
+			_free_root();
+
+#ifdef GLOBALNIL_DISABLED
+			memdelete_allocator<Element, A>(_nil);
+#endif
+		}
+	};
+
+	_Data _data;
+
+	inline void _set_color(Element *p_node, int p_color) {
+		ERR_FAIL_COND(p_node == _data._nil && p_color == RED);
+		p_node->color = p_color;
+	}
+
+	inline void _rotate_left(Element *p_node) {
+		Element *r = p_node->right;
+		p_node->right = r->left;
+		if (r->left != _data._nil) {
+			r->left->parent = p_node;
+		}
+		r->parent = p_node->parent;
+		if (p_node == p_node->parent->left) {
+			p_node->parent->left = r;
+		} else {
+			p_node->parent->right = r;
+		}
+
+		r->left = p_node;
+		p_node->parent = r;
+	}
+
+	inline void _rotate_right(Element *p_node) {
+		Element *l = p_node->left;
+		p_node->left = l->right;
+		if (l->right != _data._nil) {
+			l->right->parent = p_node;
+		}
+		l->parent = p_node->parent;
+		if (p_node == p_node->parent->right) {
+			p_node->parent->right = l;
+		} else {
+			p_node->parent->left = l;
+		}
+
+		l->right = p_node;
+		p_node->parent = l;
+	}
+
+	inline Element *_successor(Element *p_node) const {
+		Element *node = p_node;
+
+		if (node->right != _data._nil) {
+			node = node->right;
+			while (node->left != _data._nil) { /* returns the minimum of the right subtree of node */
+				node = node->left;
+			}
+			return node;
+		} else {
+			while (node == node->parent->right) {
+				node = node->parent;
+			}
+
+			if (node->parent == _data._root) {
+				return nullptr; // No successor, as p_node = last node
+			}
+			return node->parent;
+		}
+	}
+
+	inline Element *_predecessor(Element *p_node) const {
+		Element *node = p_node;
+
+		if (node->left != _data._nil) {
+			node = node->left;
+			while (node->right != _data._nil) { /* returns the minimum of the left subtree of node */
+				node = node->right;
+			}
+			return node;
+		} else {
+			while (node == node->parent->left) {
+				node = node->parent;
+			}
+
+			if (node == _data._root) {
+				return nullptr; // No predecessor, as p_node = first node.
+			}
+			return node->parent;
+		}
+	}
+
+	Element *_find(const T &p_value) const {
+		Element *node = _data._root->left;
+		C less;
+
+		while (node != _data._nil) {
+			if (less(p_value, node->value)) {
+				node = node->left;
+			} else if (less(node->value, p_value)) {
+				node = node->right;
+			} else {
+				return node; // found
+			}
+		}
+
+		return nullptr;
+	}
+
+	Element *_lower_bound(const T &p_value) const {
+		Element *node = _data._root->left;
+		Element *prev = nullptr;
+		C less;
+
+		while (node != _data._nil) {
+			prev = node;
+
+			if (less(p_value, node->value)) {
+				node = node->left;
+			} else if (less(node->value, p_value)) {
+				node = node->right;
+			} else {
+				return node; // found
+			}
+		}
+
+		if (prev == nullptr) {
+			return nullptr; // tree empty
+		}
+
+		if (less(prev->value, p_value)) {
+			prev = prev->_next;
+		}
+
+		return prev;
+	}
+
+	void _insert_rb_fix(Element *p_new_node) {
+		Element *node = p_new_node;
+		Element *nparent = node->parent;
+		Element *ngrand_parent;
+
+		while (nparent->color == RED) {
+			ngrand_parent = nparent->parent;
+
+			if (nparent == ngrand_parent->left) {
+				if (ngrand_parent->right->color == RED) {
+					_set_color(nparent, BLACK);
+					_set_color(ngrand_parent->right, BLACK);
+					_set_color(ngrand_parent, RED);
+					node = ngrand_parent;
+					nparent = node->parent;
+				} else {
+					if (node == nparent->right) {
+						_rotate_left(nparent);
+						node = nparent;
+						nparent = node->parent;
+					}
+					_set_color(nparent, BLACK);
+					_set_color(ngrand_parent, RED);
+					_rotate_right(ngrand_parent);
+				}
+			} else {
+				if (ngrand_parent->left->color == RED) {
+					_set_color(nparent, BLACK);
+					_set_color(ngrand_parent->left, BLACK);
+					_set_color(ngrand_parent, RED);
+					node = ngrand_parent;
+					nparent = node->parent;
+				} else {
+					if (node == nparent->left) {
+						_rotate_right(nparent);
+						node = nparent;
+						nparent = node->parent;
+					}
+					_set_color(nparent, BLACK);
+					_set_color(ngrand_parent, RED);
+					_rotate_left(ngrand_parent);
+				}
+			}
+		}
+
+		_set_color(_data._root->left, BLACK);
+	}
+
+	Element *_insert(const T &p_value) {
+		Element *new_parent = _data._root;
+		Element *node = _data._root->left;
+		C less;
+
+		while (node != _data._nil) {
+			new_parent = node;
+
+			if (less(p_value, node->value)) {
+				node = node->left;
+			} else if (less(node->value, p_value)) {
+				node = node->right;
+			} else {
+				return node; // Return existing node
+			}
+		}
+
+		Element *new_node = memnew_allocator(Element, A);
+		new_node->parent = new_parent;
+		new_node->right = _data._nil;
+		new_node->left = _data._nil;
+		new_node->value = p_value;
+		// new_node->data=_data;
+
+		if (new_parent == _data._root || less(p_value, new_parent->value)) {
+			new_parent->left = new_node;
+		} else {
+			new_parent->right = new_node;
+		}
+
+		new_node->_next = _successor(new_node);
+		new_node->_prev = _predecessor(new_node);
+		if (new_node->_next) {
+			new_node->_next->_prev = new_node;
+		}
+		if (new_node->_prev) {
+			new_node->_prev->_next = new_node;
+		}
+
+		_data.size_cache++;
+		_insert_rb_fix(new_node);
+		return new_node;
+	}
+
+	void _erase_fix_rb(Element *p_node) {
+		Element *root = _data._root->left;
+		Element *node = _data._nil;
+		Element *sibling = p_node;
+		Element *parent = sibling->parent;
+
+		while (node != root) { // If red node found, will exit at a break
+			if (sibling->color == RED) {
+				_set_color(sibling, BLACK);
+				_set_color(parent, RED);
+				if (sibling == parent->right) {
+					sibling = sibling->left;
+					_rotate_left(parent);
+				} else {
+					sibling = sibling->right;
+					_rotate_right(parent);
+				}
+			}
+			if ((sibling->left->color == BLACK) && (sibling->right->color == BLACK)) {
+				_set_color(sibling, RED);
+				if (parent->color == RED) {
+					_set_color(parent, BLACK);
+					break;
+				} else { // loop: haven't found any red nodes yet
+					node = parent;
+					parent = node->parent;
+					sibling = (node == parent->left) ? parent->right : parent->left;
+				}
+			} else {
+				if (sibling == parent->right) {
+					if (sibling->right->color == BLACK) {
+						_set_color(sibling->left, BLACK);
+						_set_color(sibling, RED);
+						_rotate_right(sibling);
+						sibling = sibling->parent;
+					}
+					_set_color(sibling, parent->color);
+					_set_color(parent, BLACK);
+					_set_color(sibling->right, BLACK);
+					_rotate_left(parent);
+					break;
+				} else {
+					if (sibling->left->color == BLACK) {
+						_set_color(sibling->right, BLACK);
+						_set_color(sibling, RED);
+						_rotate_left(sibling);
+						sibling = sibling->parent;
+					}
+
+					_set_color(sibling, parent->color);
+					_set_color(parent, BLACK);
+					_set_color(sibling->left, BLACK);
+					_rotate_right(parent);
+					break;
+				}
+			}
+		}
+
+		ERR_FAIL_COND(_data._nil->color != BLACK);
+	}
+
+	void _erase(Element *p_node) {
+		Element *rp = ((p_node->left == _data._nil) || (p_node->right == _data._nil)) ? p_node : p_node->_next;
+		Element *node = (rp->left == _data._nil) ? rp->right : rp->left;
+
+		Element *sibling;
+		if (rp == rp->parent->left) {
+			rp->parent->left = node;
+			sibling = rp->parent->right;
+		} else {
+			rp->parent->right = node;
+			sibling = rp->parent->left;
+		}
+
+		if (node->color == RED) {
+			node->parent = rp->parent;
+			_set_color(node, BLACK);
+		} else if (rp->color == BLACK && rp->parent != _data._root) {
+			_erase_fix_rb(sibling);
+		}
+
+		if (rp != p_node) {
+			ERR_FAIL_COND(rp == _data._nil);
+
+			rp->left = p_node->left;
+			rp->right = p_node->right;
+			rp->parent = p_node->parent;
+			rp->color = p_node->color;
+			if (p_node->left != _data._nil) {
+				p_node->left->parent = rp;
+			}
+			if (p_node->right != _data._nil) {
+				p_node->right->parent = rp;
+			}
+
+			if (p_node == p_node->parent->left) {
+				p_node->parent->left = rp;
+			} else {
+				p_node->parent->right = rp;
+			}
+		}
+
+		if (p_node->_next) {
+			p_node->_next->_prev = p_node->_prev;
+		}
+		if (p_node->_prev) {
+			p_node->_prev->_next = p_node->_next;
+		}
+
+		memdelete_allocator<Element, A>(p_node);
+		_data.size_cache--;
+		ERR_FAIL_COND(_data._nil->color == RED);
+	}
+
+	void _calculate_depth(Element *p_element, int &max_d, int d) const {
+		if (p_element == _data._nil) {
+			return;
+		}
+
+		_calculate_depth(p_element->left, max_d, d + 1);
+		_calculate_depth(p_element->right, max_d, d + 1);
+
+		if (d > max_d) {
+			max_d = d;
+		}
+	}
+
+	void _cleanup_tree(Element *p_element) {
+		if (p_element == _data._nil) {
+			return;
+		}
+
+		_cleanup_tree(p_element->left);
+		_cleanup_tree(p_element->right);
+		memdelete_allocator<Element, A>(p_element);
+	}
+
+	void _copy_from(const Set &p_set) {
+		clear();
+		// not the fastest way, but safeset to write.
+		for (Element *I = p_set.front(); I; I = I->next()) {
+			insert(I->get());
+		}
+	}
+
+public:
+	const Element *find(const T &p_value) const {
+		if (!_data._root) {
+			return nullptr;
+		}
+
+		const Element *res = _find(p_value);
+		return res;
+	}
+
+	Element *find(const T &p_value) {
+		if (!_data._root) {
+			return nullptr;
+		}
+
+		Element *res = _find(p_value);
+		return res;
+	}
+
+	Element *lower_bound(const T &p_value) const {
+		if (!_data._root) {
+			return nullptr;
+		}
+		return _lower_bound(p_value);
+	}
+
+	bool has(const T &p_value) const {
+		return find(p_value) != nullptr;
+	}
+
+	Element *insert(const T &p_value) {
+		if (!_data._root) {
+			_data._create_root();
+		}
+		return _insert(p_value);
+	}
+
+	void erase(Element *p_element) {
+		if (!_data._root || !p_element) {
+			return;
+		}
+
+		_erase(p_element);
+		if (_data.size_cache == 0 && _data._root) {
+			_data._free_root();
+		}
+	}
+
+	bool erase(const T &p_value) {
+		if (!_data._root) {
+			return false;
+		}
+
+		Element *e = find(p_value);
+		if (!e) {
+			return false;
+		}
+
+		_erase(e);
+		if (_data.size_cache == 0 && _data._root) {
+			_data._free_root();
+		}
+		return true;
+	}
+
+	Element *front() const {
+		if (!_data._root) {
+			return nullptr;
+		}
+
+		Element *e = _data._root->left;
+		if (e == _data._nil) {
+			return nullptr;
+		}
+
+		while (e->left != _data._nil) {
+			e = e->left;
+		}
+
+		return e;
+	}
+
+	Element *back() const {
+		if (!_data._root) {
+			return nullptr;
+		}
+
+		Element *e = _data._root->left;
+		if (e == _data._nil) {
+			return nullptr;
+		}
+
+		while (e->right != _data._nil) {
+			e = e->right;
+		}
+
+		return e;
+	}
+
+	inline bool is_empty() const { return _data.size_cache == 0; }
+	inline int size() const { return _data.size_cache; }
+
+	int calculate_depth() const {
+		// used for debug mostly
+		if (!_data._root) {
+			return 0;
+		}
+
+		int max_d = 0;
+		_calculate_depth(_data._root->left, max_d, 0);
+		return max_d;
+	}
+
+	void clear() {
+		if (!_data._root) {
+			return;
+		}
+
+		_cleanup_tree(_data._root->left);
+		_data._root->left = _data._nil;
+		_data.size_cache = 0;
+		_data._free_root();
+	}
+
+	void operator=(const Set &p_set) {
+		_copy_from(p_set);
+	}
+
+	Set(const Set &p_set) {
+		_copy_from(p_set);
+	}
+
+	_FORCE_INLINE_ Set() {}
+
+	~Set() {
+		clear();
+	}
+};
+
+} // namespace godot
+
+#endif // ! SET_HPP

+ 323 - 0
include/godot_cpp/templates/sort_array.hpp

@@ -0,0 +1,323 @@
+/*************************************************************************/
+/*  sort_array.hpp                                                       */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* 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 SORT_ARRAY_HPP
+#define SORT_ARRAY_HPP
+
+#include <godot_cpp/core/error_macros.hpp>
+
+namespace godot {
+
+#define ERR_BAD_COMPARE(cond)                                         \
+	if (unlikely(cond)) {                                             \
+		ERR_PRINT("bad comparison function; sorting will be broken"); \
+		break;                                                        \
+	}
+
+template <class T>
+struct _DefaultComparator {
+	_FORCE_INLINE_ bool operator()(const T &a, const T &b) const { return (a < b); }
+};
+
+#ifdef DEBUG_ENABLED
+#define SORT_ARRAY_VALIDATE_ENABLED true
+#else
+#define SORT_ARRAY_VALIDATE_ENABLED false
+#endif
+
+template <class T, class Comparator = _DefaultComparator<T>, bool Validate = SORT_ARRAY_VALIDATE_ENABLED>
+class SortArray {
+	enum {
+		INTROSORT_THRESHOLD = 16
+	};
+
+public:
+	Comparator compare;
+
+	inline const T &median_of_3(const T &a, const T &b, const T &c) const {
+		if (compare(a, b)) {
+			if (compare(b, c)) {
+				return b;
+			} else if (compare(a, c)) {
+				return c;
+			} else {
+				return a;
+			}
+		} else if (compare(a, c)) {
+			return a;
+		} else if (compare(b, c)) {
+			return c;
+		} else {
+			return b;
+		}
+	}
+
+	inline int bitlog(int n) const {
+		int k;
+		for (k = 0; n != 1; n >>= 1) {
+			++k;
+		}
+		return k;
+	}
+
+	/* Heap / Heapsort functions */
+
+	inline void push_heap(int p_first, int p_hole_idx, int p_top_index, T p_value, T *p_array) const {
+		int parent = (p_hole_idx - 1) / 2;
+		while (p_hole_idx > p_top_index && compare(p_array[p_first + parent], p_value)) {
+			p_array[p_first + p_hole_idx] = p_array[p_first + parent];
+			p_hole_idx = parent;
+			parent = (p_hole_idx - 1) / 2;
+		}
+		p_array[p_first + p_hole_idx] = p_value;
+	}
+
+	inline void pop_heap(int p_first, int p_last, int p_result, T p_value, T *p_array) const {
+		p_array[p_result] = p_array[p_first];
+		adjust_heap(p_first, 0, p_last - p_first, p_value, p_array);
+	}
+	inline void pop_heap(int p_first, int p_last, T *p_array) const {
+		pop_heap(p_first, p_last - 1, p_last - 1, p_array[p_last - 1], p_array);
+	}
+
+	inline void adjust_heap(int p_first, int p_hole_idx, int p_len, T p_value, T *p_array) const {
+		int top_index = p_hole_idx;
+		int second_child = 2 * p_hole_idx + 2;
+
+		while (second_child < p_len) {
+			if (compare(p_array[p_first + second_child], p_array[p_first + (second_child - 1)])) {
+				second_child--;
+			}
+
+			p_array[p_first + p_hole_idx] = p_array[p_first + second_child];
+			p_hole_idx = second_child;
+			second_child = 2 * (second_child + 1);
+		}
+
+		if (second_child == p_len) {
+			p_array[p_first + p_hole_idx] = p_array[p_first + (second_child - 1)];
+			p_hole_idx = second_child - 1;
+		}
+		push_heap(p_first, p_hole_idx, top_index, p_value, p_array);
+	}
+
+	inline void sort_heap(int p_first, int p_last, T *p_array) const {
+		while (p_last - p_first > 1) {
+			pop_heap(p_first, p_last--, p_array);
+		}
+	}
+
+	inline void make_heap(int p_first, int p_last, T *p_array) const {
+		if (p_last - p_first < 2) {
+			return;
+		}
+		int len = p_last - p_first;
+		int parent = (len - 2) / 2;
+
+		while (true) {
+			adjust_heap(p_first, parent, len, p_array[p_first + parent], p_array);
+			if (parent == 0) {
+				return;
+			}
+			parent--;
+		}
+	}
+
+	inline void partial_sort(int p_first, int p_last, int p_middle, T *p_array) const {
+		make_heap(p_first, p_middle, p_array);
+		for (int i = p_middle; i < p_last; i++) {
+			if (compare(p_array[i], p_array[p_first])) {
+				pop_heap(p_first, p_middle, i, p_array[i], p_array);
+			}
+		}
+		sort_heap(p_first, p_middle, p_array);
+	}
+
+	inline void partial_select(int p_first, int p_last, int p_middle, T *p_array) const {
+		make_heap(p_first, p_middle, p_array);
+		for (int i = p_middle; i < p_last; i++) {
+			if (compare(p_array[i], p_array[p_first])) {
+				pop_heap(p_first, p_middle, i, p_array[i], p_array);
+			}
+		}
+	}
+
+	inline int partitioner(int p_first, int p_last, T p_pivot, T *p_array) const {
+		const int unmodified_first = p_first;
+		const int unmodified_last = p_last;
+
+		while (true) {
+			while (compare(p_array[p_first], p_pivot)) {
+				if (Validate) {
+					ERR_BAD_COMPARE(p_first == unmodified_last - 1);
+				}
+				p_first++;
+			}
+			p_last--;
+			while (compare(p_pivot, p_array[p_last])) {
+				if (Validate) {
+					ERR_BAD_COMPARE(p_last == unmodified_first);
+				}
+				p_last--;
+			}
+
+			if (!(p_first < p_last)) {
+				return p_first;
+			}
+
+			SWAP(p_array[p_first], p_array[p_last]);
+			p_first++;
+		}
+	}
+
+	inline void introsort(int p_first, int p_last, T *p_array, int p_max_depth) const {
+		while (p_last - p_first > INTROSORT_THRESHOLD) {
+			if (p_max_depth == 0) {
+				partial_sort(p_first, p_last, p_last, p_array);
+				return;
+			}
+
+			p_max_depth--;
+
+			int cut = partitioner(
+					p_first,
+					p_last,
+					median_of_3(
+							p_array[p_first],
+							p_array[p_first + (p_last - p_first) / 2],
+							p_array[p_last - 1]),
+					p_array);
+
+			introsort(cut, p_last, p_array, p_max_depth);
+			p_last = cut;
+		}
+	}
+
+	inline void introselect(int p_first, int p_nth, int p_last, T *p_array, int p_max_depth) const {
+		while (p_last - p_first > 3) {
+			if (p_max_depth == 0) {
+				partial_select(p_first, p_nth + 1, p_last, p_array);
+				SWAP(p_first, p_nth);
+				return;
+			}
+
+			p_max_depth--;
+
+			int cut = partitioner(
+					p_first,
+					p_last,
+					median_of_3(
+							p_array[p_first],
+							p_array[p_first + (p_last - p_first) / 2],
+							p_array[p_last - 1]),
+					p_array);
+
+			if (cut <= p_nth) {
+				p_first = cut;
+			} else {
+				p_last = cut;
+			}
+		}
+
+		insertion_sort(p_first, p_last, p_array);
+	}
+
+	inline void unguarded_linear_insert(int p_last, T p_value, T *p_array) const {
+		int next = p_last - 1;
+		while (compare(p_value, p_array[next])) {
+			if (Validate) {
+				ERR_BAD_COMPARE(next == 0);
+			}
+			p_array[p_last] = p_array[next];
+			p_last = next;
+			next--;
+		}
+		p_array[p_last] = p_value;
+	}
+
+	inline void linear_insert(int p_first, int p_last, T *p_array) const {
+		T val = p_array[p_last];
+		if (compare(val, p_array[p_first])) {
+			for (int i = p_last; i > p_first; i--) {
+				p_array[i] = p_array[i - 1];
+			}
+
+			p_array[p_first] = val;
+		} else {
+			unguarded_linear_insert(p_last, val, p_array);
+		}
+	}
+
+	inline void insertion_sort(int p_first, int p_last, T *p_array) const {
+		if (p_first == p_last) {
+			return;
+		}
+		for (int i = p_first + 1; i != p_last; i++) {
+			linear_insert(p_first, i, p_array);
+		}
+	}
+
+	inline void unguarded_insertion_sort(int p_first, int p_last, T *p_array) const {
+		for (int i = p_first; i != p_last; i++) {
+			unguarded_linear_insert(i, p_array[i], p_array);
+		}
+	}
+
+	inline void final_insertion_sort(int p_first, int p_last, T *p_array) const {
+		if (p_last - p_first > INTROSORT_THRESHOLD) {
+			insertion_sort(p_first, p_first + INTROSORT_THRESHOLD, p_array);
+			unguarded_insertion_sort(p_first + INTROSORT_THRESHOLD, p_last, p_array);
+		} else {
+			insertion_sort(p_first, p_last, p_array);
+		}
+	}
+
+	inline void sort_range(int p_first, int p_last, T *p_array) const {
+		if (p_first != p_last) {
+			introsort(p_first, p_last, p_array, bitlog(p_last - p_first) * 2);
+			final_insertion_sort(p_first, p_last, p_array);
+		}
+	}
+
+	inline void sort(T *p_array, int p_len) const {
+		sort_range(0, p_len, p_array);
+	}
+
+	inline void nth_element(int p_first, int p_last, int p_nth, T *p_array) const {
+		if (p_first == p_last || p_nth == p_last) {
+			return;
+		}
+		introselect(p_first, p_nth, p_last, p_array, bitlog(p_last - p_first) * 2);
+	}
+};
+
+} // namespace godot
+
+#endif // ! SORT_ARRAY_HPP

+ 54 - 0
include/godot_cpp/templates/spin_lock.hpp

@@ -0,0 +1,54 @@
+/*************************************************************************/
+/*  spin_lock.hpp                                                        */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* 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 SPIN_LOCK_HPP
+#define SPIN_LOCK_HPP
+
+#include <atomic>
+
+namespace godot {
+
+class SpinLock {
+	std::atomic_flag locked = ATOMIC_FLAG_INIT;
+
+public:
+	_ALWAYS_INLINE_ void lock() {
+		while (locked.test_and_set(std::memory_order_acquire)) {
+			;
+		}
+	}
+	_ALWAYS_INLINE_ void unlock() {
+		locked.clear(std::memory_order_release);
+	}
+};
+
+} // namespace godot
+
+#endif // ! SPIN_LOCK_HPP

+ 205 - 0
include/godot_cpp/templates/thread_work_pool.hpp

@@ -0,0 +1,205 @@
+/*************************************************************************/
+/*  thread_work_pool.hpp                                                 */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* 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 THREAD_WORK_POOL_HPP
+#define THREAD_WORK_POOL_HPP
+
+#include <godot_cpp/classes/os.hpp>
+#include <godot_cpp/classes/semaphore.hpp>
+#include <godot_cpp/core/error_macros.hpp>
+#include <godot_cpp/core/memory.hpp>
+
+#include <thread>
+
+#include <atomic>
+
+namespace godot {
+
+class ThreadWorkPool {
+	std::atomic<uint32_t> index;
+
+	struct BaseWork {
+		std::atomic<uint32_t> *index = nullptr;
+		uint32_t max_elements = 0;
+		virtual void work() = 0;
+		virtual ~BaseWork() = default;
+	};
+
+	template <class C, class M, class U>
+	struct Work : public BaseWork {
+		C *instance;
+		M method;
+		U userdata;
+		virtual void work() {
+			while (true) {
+				uint32_t work_index = index->fetch_add(1, std::memory_order_relaxed);
+				if (work_index >= max_elements) {
+					break;
+				}
+				(instance->*method)(work_index, userdata);
+			}
+		}
+	};
+
+	struct ThreadData {
+		std::thread thread;
+		Semaphore start;
+		Semaphore completed;
+		std::atomic<bool> exit;
+		BaseWork *work;
+	};
+
+	ThreadData *threads = nullptr;
+	uint32_t thread_count = 0;
+	uint32_t threads_working = 0;
+	BaseWork *current_work = nullptr;
+
+	static void _thread_function(void *p_user) {
+		ThreadData *thread = static_cast<ThreadData *>(p_user);
+		while (true) {
+			thread->start.wait();
+			if (thread->exit.load()) {
+				break;
+			}
+			thread->work->work();
+			thread->completed.post();
+		}
+	}
+
+public:
+	template <class C, class M, class U>
+	void begin_work(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) {
+		ERR_FAIL_COND(!threads); // never initialized
+		ERR_FAIL_COND(current_work != nullptr);
+
+		index.store(0, std::memory_order_release);
+
+		Work<C, M, U> *w = new (Work<C, M, U>);
+		w->instance = p_instance;
+		w->userdata = p_userdata;
+		w->method = p_method;
+		w->index = &index;
+		w->max_elements = p_elements;
+
+		current_work = w;
+
+		threads_working = Math::min(p_elements, thread_count);
+
+		for (uint32_t i = 0; i < threads_working; i++) {
+			threads[i].work = w;
+			threads[i].start.post();
+		}
+	}
+
+	bool is_working() const {
+		return current_work != nullptr;
+	}
+
+	bool is_done_dispatching() const {
+		ERR_FAIL_COND_V(current_work == nullptr, true);
+		return index.load(std::memory_order_acquire) >= current_work->max_elements;
+	}
+
+	uint32_t get_work_index() const {
+		ERR_FAIL_COND_V(current_work == nullptr, 0);
+		uint32_t idx = index.load(std::memory_order_acquire);
+		return Math::min(idx, current_work->max_elements);
+	}
+
+	void end_work() {
+		ERR_FAIL_COND(current_work == nullptr);
+		for (uint32_t i = 0; i < threads_working; i++) {
+			threads[i].completed.wait();
+			threads[i].work = nullptr;
+		}
+
+		threads_working = 0;
+		delete current_work;
+		current_work = nullptr;
+	}
+
+	template <class C, class M, class U>
+	void do_work(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) {
+		switch (p_elements) {
+			case 0:
+				// Nothing to do, so do nothing.
+				break;
+			case 1:
+				// No value in pushing the work to another thread if it's a single job
+				// and we're going to wait for it to finish. Just run it right here.
+				(p_instance->*p_method)(0, p_userdata);
+				break;
+			default:
+				// Multiple jobs to do; commence threaded business.
+				begin_work(p_elements, p_instance, p_method, p_userdata);
+				end_work();
+		}
+	}
+
+	_FORCE_INLINE_ int get_thread_count() const { return thread_count; }
+	void init(int p_thread_count = -1) {
+		ERR_FAIL_COND(threads != nullptr);
+		if (p_thread_count < 0) {
+			p_thread_count = OS::get_singleton()->get_processor_count();
+		}
+
+		thread_count = p_thread_count;
+		threads = new ThreadData[thread_count];
+
+		for (uint32_t i = 0; i < thread_count; i++) {
+			threads[i].exit.store(false);
+			threads[i].thread = std::thread(&ThreadWorkPool::_thread_function, &threads[i]);
+		}
+	}
+
+	void finish() {
+		if (threads == nullptr) {
+			return;
+		}
+
+		for (uint32_t i = 0; i < thread_count; i++) {
+			threads[i].exit.store(true);
+			threads[i].start.post();
+		}
+		for (uint32_t i = 0; i < thread_count; i++) {
+			threads[i].thread.join();
+		}
+
+		delete[](threads);
+		threads = nullptr;
+	}
+	~ThreadWorkPool() {
+		finish();
+	}
+};
+
+} // namespace godot
+
+#endif // ! THREAD_WORK_POOL_HPP

+ 321 - 0
include/godot_cpp/templates/vector.hpp

@@ -0,0 +1,321 @@
+/*************************************************************************/
+/*  vector.hpp                                                           */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* 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 VECTOR_HPP
+#define VECTOR_HPP
+
+/**
+ * @class Vector
+ * Vector container. Regular Vector Container. Use with care and for smaller arrays when possible. Use Vector for large arrays.
+ */
+
+#include <godot_cpp/core/error_macros.hpp>
+#include <godot_cpp/core/memory.hpp>
+#include <godot_cpp/templates/cowdata.hpp>
+#include <godot_cpp/templates/search_array.hpp>
+#include <godot_cpp/templates/sort_array.hpp>
+
+#include <climits>
+#include <initializer_list>
+
+namespace godot {
+
+template <class T>
+class VectorWriteProxy {
+public:
+	_FORCE_INLINE_ T &operator[](int p_index) {
+		CRASH_BAD_INDEX(p_index, ((Vector<T> *)(this))->_cowdata.size());
+
+		return ((Vector<T> *)(this))->_cowdata.ptrw()[p_index];
+	}
+};
+
+template <class T>
+class Vector {
+	friend class VectorWriteProxy<T>;
+
+public:
+	VectorWriteProxy<T> write;
+
+private:
+	CowData<T> _cowdata;
+
+public:
+	bool push_back(T p_elem);
+	_FORCE_INLINE_ bool append(const T &p_elem) { return push_back(p_elem); } // alias
+	void fill(T p_elem);
+
+	void remove_at(int p_index) { _cowdata.remove_at(p_index); }
+	void erase(const T &p_val) {
+		int idx = find(p_val);
+		if (idx >= 0) {
+			remove_at(idx);
+		}
+	}
+	void reverse();
+
+	_FORCE_INLINE_ T *ptrw() { return _cowdata.ptrw(); }
+	_FORCE_INLINE_ const T *ptr() const { return _cowdata.ptr(); }
+	_FORCE_INLINE_ void clear() { resize(0); }
+	_FORCE_INLINE_ bool is_empty() const { return _cowdata.is_empty(); }
+
+	_FORCE_INLINE_ T get(int p_index) { return _cowdata.get(p_index); }
+	_FORCE_INLINE_ const T &get(int p_index) const { return _cowdata.get(p_index); }
+	_FORCE_INLINE_ void set(int p_index, const T &p_elem) { _cowdata.set(p_index, p_elem); }
+	_FORCE_INLINE_ int size() const { return _cowdata.size(); }
+	Error resize(int p_size) { return _cowdata.resize(p_size); }
+	_FORCE_INLINE_ const T &operator[](int p_index) const { return _cowdata.get(p_index); }
+	Error insert(int p_pos, T p_val) { return _cowdata.insert(p_pos, p_val); }
+	int find(const T &p_val, int p_from = 0) const { return _cowdata.find(p_val, p_from); }
+
+	void append_array(Vector<T> p_other);
+
+	_FORCE_INLINE_ bool has(const T &p_val) const { return find(p_val) != -1; }
+
+	template <class C>
+	void sort_custom() {
+		int len = _cowdata.size();
+		if (len == 0) {
+			return;
+		}
+
+		T *data = ptrw();
+		SortArray<T, C> sorter;
+		sorter.sort(data, len);
+	}
+
+	void sort() {
+		sort_custom<_DefaultComparator<T>>();
+	}
+
+	int bsearch(const T &p_value, bool p_before) {
+		SearchArray<T> search;
+		return search.bisect(ptrw(), size(), p_value, p_before);
+	}
+
+	Vector<T> duplicate() {
+		return *this;
+	}
+
+	void ordered_insert(const T &p_val) {
+		int i;
+		for (i = 0; i < _cowdata.size(); i++) {
+			if (p_val < operator[](i)) {
+				break;
+			}
+		}
+		insert(i, p_val);
+	}
+
+	inline void operator=(const Vector &p_from) {
+		_cowdata._ref(p_from._cowdata);
+	}
+
+	Vector<uint8_t> to_byte_array() const {
+		Vector<uint8_t> ret;
+		ret.resize(size() * sizeof(T));
+		memcpy(ret.ptrw(), ptr(), sizeof(T) * size());
+		return ret;
+	}
+
+	Vector<T> slice(int p_begin, int p_end = INT_MAX) const {
+		Vector<T> result;
+
+		const int s = size();
+
+		int begin = Math::clamp(p_begin, -s, s);
+		if (begin < 0) {
+			begin += s;
+		}
+		int end = Math::clamp(p_end, -s, s);
+		if (end < 0) {
+			end += s;
+		}
+
+		ERR_FAIL_COND_V(begin > end, result);
+
+		int result_size = end - begin;
+		result.resize(result_size);
+
+		const T *const r = ptr();
+		T *const w = result.ptrw();
+		for (int i = 0; i < result_size; ++i) {
+			w[i] = r[begin + i];
+		}
+
+		return result;
+	}
+
+	bool operator==(const Vector<T> &p_arr) const {
+		int s = size();
+		if (s != p_arr.size()) {
+			return false;
+		}
+		for (int i = 0; i < s; i++) {
+			if (operator[](i) != p_arr[i]) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+	bool operator!=(const Vector<T> &p_arr) const {
+		int s = size();
+		if (s != p_arr.size()) {
+			return true;
+		}
+		for (int i = 0; i < s; i++) {
+			if (operator[](i) != p_arr[i]) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	struct Iterator {
+		_FORCE_INLINE_ T &operator*() const {
+			return *elem_ptr;
+		}
+		_FORCE_INLINE_ T *operator->() const { return elem_ptr; }
+		_FORCE_INLINE_ Iterator &operator++() {
+			elem_ptr++;
+			return *this;
+		}
+		_FORCE_INLINE_ Iterator &operator--() {
+			elem_ptr--;
+			return *this;
+		}
+
+		_FORCE_INLINE_ bool operator==(const Iterator &b) const { return elem_ptr == b.elem_ptr; }
+		_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return elem_ptr != b.elem_ptr; }
+
+		Iterator(T *p_ptr) { elem_ptr = p_ptr; }
+		Iterator() {}
+		Iterator(const Iterator &p_it) { elem_ptr = p_it.elem_ptr; }
+
+	private:
+		T *elem_ptr = nullptr;
+	};
+
+	struct ConstIterator {
+		_FORCE_INLINE_ const T &operator*() const {
+			return *elem_ptr;
+		}
+		_FORCE_INLINE_ const T *operator->() const { return elem_ptr; }
+		_FORCE_INLINE_ ConstIterator &operator++() {
+			elem_ptr++;
+			return *this;
+		}
+		_FORCE_INLINE_ ConstIterator &operator--() {
+			elem_ptr--;
+			return *this;
+		}
+
+		_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return elem_ptr == b.elem_ptr; }
+		_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return elem_ptr != b.elem_ptr; }
+
+		ConstIterator(const T *p_ptr) { elem_ptr = p_ptr; }
+		ConstIterator() {}
+		ConstIterator(const ConstIterator &p_it) { elem_ptr = p_it.elem_ptr; }
+
+	private:
+		const T *elem_ptr = nullptr;
+	};
+
+	_FORCE_INLINE_ Iterator begin() {
+		return Iterator(ptrw());
+	}
+	_FORCE_INLINE_ Iterator end() {
+		return Iterator(ptrw() + size());
+	}
+
+	_FORCE_INLINE_ ConstIterator begin() const {
+		return ConstIterator(ptr());
+	}
+	_FORCE_INLINE_ ConstIterator end() const {
+		return ConstIterator(ptr() + size());
+	}
+
+	_FORCE_INLINE_ Vector() {}
+	_FORCE_INLINE_ Vector(std::initializer_list<T> p_init) {
+		Error err = _cowdata.resize(p_init.size());
+		ERR_FAIL_COND(err);
+
+		int i = 0;
+		for (const T &element : p_init) {
+			_cowdata.set(i++, element);
+		}
+	}
+	_FORCE_INLINE_ Vector(const Vector &p_from) { _cowdata._ref(p_from._cowdata); }
+
+	_FORCE_INLINE_ ~Vector() {}
+};
+
+template <class T>
+void Vector<T>::reverse() {
+	for (int i = 0; i < size() / 2; i++) {
+		T *p = ptrw();
+		SWAP(p[i], p[size() - i - 1]);
+	}
+}
+
+template <class T>
+void Vector<T>::append_array(Vector<T> p_other) {
+	const int ds = p_other.size();
+	if (ds == 0) {
+		return;
+	}
+	const int bs = size();
+	resize(bs + ds);
+	for (int i = 0; i < ds; ++i) {
+		ptrw()[bs + i] = p_other[i];
+	}
+}
+
+template <class T>
+bool Vector<T>::push_back(T p_elem) {
+	Error err = resize(size() + 1);
+	ERR_FAIL_COND_V(err, true);
+	set(size() - 1, p_elem);
+
+	return false;
+}
+
+template <class T>
+void Vector<T>::fill(T p_elem) {
+	T *p = ptrw();
+	for (int i = 0; i < size(); i++) {
+		p[i] = p_elem;
+	}
+}
+
+} // namespace godot
+
+#endif // ! VECTOR_HPP

+ 204 - 0
include/godot_cpp/templates/vmap.hpp

@@ -0,0 +1,204 @@
+/*************************************************************************/
+/*  vmap.hpp                                                             */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* 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 VMAP_HPP
+#define VMAP_HPP
+
+#include <godot_cpp/templates/cowdata.hpp>
+
+namespace godot {
+
+template <class T, class V>
+class VMap {
+public:
+	struct Pair {
+		T key;
+		V value;
+
+		_FORCE_INLINE_ Pair() {}
+
+		_FORCE_INLINE_ Pair(const T &p_key, const V &p_value) {
+			key = p_key;
+			value = p_value;
+		}
+	};
+
+private:
+	CowData<Pair> _cowdata;
+
+	_FORCE_INLINE_ int _find(const T &p_val, bool &r_exact) const {
+		r_exact = false;
+		if (_cowdata.is_empty()) {
+			return 0;
+		}
+
+		int low = 0;
+		int high = _cowdata.size() - 1;
+		const Pair *a = _cowdata.ptr();
+		int middle = 0;
+
+#ifdef DEBUG_ENABLED
+		if (low > high) {
+			ERR_PRINT("low > high, this may be a bug");
+		}
+#endif
+		while (low <= high) {
+			middle = (low + high) / 2;
+
+			if (p_val < a[middle].key) {
+				high = middle - 1; // search low end of array
+			} else if (a[middle].key < p_val) {
+				low = middle + 1; // search high end of array
+			} else {
+				r_exact = true;
+				return middle;
+			}
+		}
+
+		// return the position where this would be inserted
+		if (a[middle].key < p_val) {
+			middle++;
+		}
+		return middle;
+	}
+
+	_FORCE_INLINE_ int _find_exact(const T &p_val) const {
+		if (_cowdata.is_empty()) {
+			return -1;
+		}
+
+		int low = 0;
+		int high = _cowdata.size() - 1;
+		int middle;
+		const Pair *a = _cowdata.ptr();
+
+		while (low <= high) {
+			middle = (low + high) / 2;
+
+			if (p_val < a[middle].key) {
+				high = middle - 1; // search low end of array
+			} else if (a[middle].key < p_val) {
+				low = middle + 1; // search high end of array
+			} else {
+				return middle;
+			}
+		}
+
+		return -1;
+	}
+
+public:
+	int insert(const T &p_key, const V &p_val) {
+		bool exact;
+		int pos = _find(p_key, exact);
+		if (exact) {
+			_cowdata.get_m(pos).value = p_val;
+			return pos;
+		}
+		_cowdata.insert(pos, Pair(p_key, p_val));
+		return pos;
+	}
+
+	bool has(const T &p_val) const {
+		return _find_exact(p_val) != -1;
+	}
+
+	void erase(const T &p_val) {
+		int pos = _find_exact(p_val);
+		if (pos < 0) {
+			return;
+		}
+		_cowdata.remove_at(pos);
+	}
+
+	int find(const T &p_val) const {
+		return _find_exact(p_val);
+	}
+
+	int find_nearest(const T &p_val) const {
+		bool exact;
+		return _find(p_val, exact);
+	}
+
+	_FORCE_INLINE_ int size() const { return _cowdata.size(); }
+	_FORCE_INLINE_ bool is_empty() const { return _cowdata.is_empty(); }
+
+	const Pair *get_array() const {
+		return _cowdata.ptr();
+	}
+
+	Pair *get_array() {
+		return _cowdata.ptrw();
+	}
+
+	const V &getv(int p_index) const {
+		return _cowdata.get(p_index).value;
+	}
+
+	V &getv(int p_index) {
+		return _cowdata.get_m(p_index).value;
+	}
+
+	const T &getk(int p_index) const {
+		return _cowdata.get(p_index).key;
+	}
+
+	T &getk(int p_index) {
+		return _cowdata.get_m(p_index).key;
+	}
+
+	inline const V &operator[](const T &p_key) const {
+		int pos = _find_exact(p_key);
+
+		CRASH_COND(pos < 0);
+
+		return _cowdata.get(pos).value;
+	}
+
+	inline V &operator[](const T &p_key) {
+		int pos = _find_exact(p_key);
+		if (pos < 0) {
+			pos = insert(p_key, V());
+		}
+
+		return _cowdata.get_m(pos).value;
+	}
+
+	_FORCE_INLINE_ VMap() {}
+	_FORCE_INLINE_ VMap(const VMap &p_from) { _cowdata._ref(p_from._cowdata); }
+
+	inline void operator=(const VMap &p_from) {
+		_cowdata._ref(p_from._cowdata);
+	}
+};
+
+} // namespace godot
+
+#endif // ! VMAP_H

+ 145 - 0
include/godot_cpp/templates/vset.hpp

@@ -0,0 +1,145 @@
+/*************************************************************************/
+/*  vset.hpp                                                             */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* 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 VSET_HPP
+#define VSET_HPP
+
+#include <godot_cpp/templates/vector.hpp>
+
+namespace godot {
+
+template <class T>
+class VSet {
+	Vector<T> _data;
+
+	_FORCE_INLINE_ int _find(const T &p_val, bool &r_exact) const {
+		r_exact = false;
+		if (_data.is_empty()) {
+			return 0;
+		}
+
+		int low = 0;
+		int high = _data.size() - 1;
+		const T *a = &_data[0];
+		int middle = 0;
+
+#ifdef DEBUG_ENABLED
+		if (low > high) {
+			ERR_PRINT("low > high, this may be a bug");
+		}
+#endif
+
+		while (low <= high) {
+			middle = (low + high) / 2;
+
+			if (p_val < a[middle]) {
+				high = middle - 1; // search low end of array
+			} else if (a[middle] < p_val) {
+				low = middle + 1; // search high end of array
+			} else {
+				r_exact = true;
+				return middle;
+			}
+		}
+
+		// return the position where this would be inserted
+		if (a[middle] < p_val) {
+			middle++;
+		}
+		return middle;
+	}
+
+	_FORCE_INLINE_ int _find_exact(const T &p_val) const {
+		if (_data.is_empty()) {
+			return -1;
+		}
+
+		int low = 0;
+		int high = _data.size() - 1;
+		int middle;
+		const T *a = &_data[0];
+
+		while (low <= high) {
+			middle = (low + high) / 2;
+
+			if (p_val < a[middle]) {
+				high = middle - 1; // search low end of array
+			} else if (a[middle] < p_val) {
+				low = middle + 1; // search high end of array
+			} else {
+				return middle;
+			}
+		}
+
+		return -1;
+	}
+
+public:
+	void insert(const T &p_val) {
+		bool exact;
+		int pos = _find(p_val, exact);
+		if (exact) {
+			return;
+		}
+		_data.insert(pos, p_val);
+	}
+
+	bool has(const T &p_val) const {
+		return _find_exact(p_val) != -1;
+	}
+
+	void erase(const T &p_val) {
+		int pos = _find_exact(p_val);
+		if (pos < 0) {
+			return;
+		}
+		_data.remove_at(pos);
+	}
+
+	int find(const T &p_val) const {
+		return _find_exact(p_val);
+	}
+
+	_FORCE_INLINE_ bool is_empty() const { return _data.is_empty(); }
+
+	_FORCE_INLINE_ int size() const { return _data.size(); }
+
+	inline T &operator[](int p_index) {
+		return _data.write[p_index];
+	}
+
+	inline const T &operator[](int p_index) const {
+		return _data[p_index];
+	}
+};
+
+} // namespace godot
+
+#endif // VSET_H

+ 90 - 0
include/godot_cpp/variant/char_utils.hpp

@@ -0,0 +1,90 @@
+/*************************************************************************/
+/*  char_utils.hpp                                                       */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* 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 CHAR_UTILS_HPP
+#define CHAR_UTILS_HPP
+
+static _FORCE_INLINE_ bool is_ascii_upper_case(char32_t c) {
+	return (c >= 'A' && c <= 'Z');
+}
+
+static _FORCE_INLINE_ bool is_ascii_lower_case(char32_t c) {
+	return (c >= 'a' && c <= 'z');
+}
+
+static _FORCE_INLINE_ bool is_digit(char32_t c) {
+	return (c >= '0' && c <= '9');
+}
+
+static _FORCE_INLINE_ bool is_hex_digit(char32_t c) {
+	return (is_digit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
+}
+
+static _FORCE_INLINE_ bool is_binary_digit(char32_t c) {
+	return (c == '0' || c == '1');
+}
+
+static _FORCE_INLINE_ bool is_ascii_char(char32_t c) {
+	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+}
+
+static _FORCE_INLINE_ bool is_ascii_alphanumeric_char(char32_t c) {
+	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9');
+}
+
+static _FORCE_INLINE_ bool is_ascii_identifier_char(char32_t c) {
+	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
+}
+
+static _FORCE_INLINE_ bool is_symbol(char32_t c) {
+	return c != '_' && ((c >= '!' && c <= '/') || (c >= ':' && c <= '@') || (c >= '[' && c <= '`') || (c >= '{' && c <= '~') || c == '\t' || c == ' ');
+}
+
+static _FORCE_INLINE_ bool is_control(char32_t p_char) {
+	return (p_char <= 0x001f) || (p_char >= 0x007f && p_char <= 0x009f);
+}
+
+static _FORCE_INLINE_ bool is_whitespace(char32_t p_char) {
+	return (p_char == ' ') || (p_char == 0x00a0) || (p_char == 0x1680) || (p_char >= 0x2000 && p_char <= 0x200a) || (p_char == 0x202f) || (p_char == 0x205f) || (p_char == 0x3000) || (p_char == 0x2028) || (p_char == 0x2029) || (p_char >= 0x0009 && p_char <= 0x000d) || (p_char == 0x0085);
+}
+
+static _FORCE_INLINE_ bool is_linebreak(char32_t p_char) {
+	return (p_char >= 0x000a && p_char <= 0x000d) || (p_char == 0x0085) || (p_char == 0x2028) || (p_char == 0x2029);
+}
+
+static _FORCE_INLINE_ bool is_punct(char32_t p_char) {
+	return (p_char >= ' ' && p_char <= '/') || (p_char >= ':' && p_char <= '@') || (p_char >= '[' && p_char <= '^') || (p_char == '`') || (p_char >= '{' && p_char <= '~') || (p_char >= 0x2000 && p_char <= 0x206f) || (p_char >= 0x3000 && p_char <= 0x303f);
+}
+
+static _FORCE_INLINE_ bool is_underscore(char32_t p_char) {
+	return (p_char == '_');
+}
+
+#endif // CHAR_UTILS_HPP

+ 1415 - 0
include/godot_cpp/variant/ucaps.hpp

@@ -0,0 +1,1415 @@
+/*************************************************************************/
+/*  ucaps.hpp                                                            */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* 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 UCAPS_HPP
+#define UCAPS_HPP
+
+// satan invented unicode?
+#define CAPS_LEN 666
+
+static const int caps_table[CAPS_LEN][2] = {
+	{ 0x0061, 0x0041 },
+	{ 0x0062, 0x0042 },
+	{ 0x0063, 0x0043 },
+	{ 0x0064, 0x0044 },
+	{ 0x0065, 0x0045 },
+	{ 0x0066, 0x0046 },
+	{ 0x0067, 0x0047 },
+	{ 0x0068, 0x0048 },
+	{ 0x0069, 0x0049 },
+	{ 0x006A, 0x004A },
+	{ 0x006B, 0x004B },
+	{ 0x006C, 0x004C },
+	{ 0x006D, 0x004D },
+	{ 0x006E, 0x004E },
+	{ 0x006F, 0x004F },
+	{ 0x0070, 0x0050 },
+	{ 0x0071, 0x0051 },
+	{ 0x0072, 0x0052 },
+	{ 0x0073, 0x0053 },
+	{ 0x0074, 0x0054 },
+	{ 0x0075, 0x0055 },
+	{ 0x0076, 0x0056 },
+	{ 0x0077, 0x0057 },
+	{ 0x0078, 0x0058 },
+	{ 0x0079, 0x0059 },
+	{ 0x007A, 0x005A },
+	{ 0x00E0, 0x00C0 },
+	{ 0x00E1, 0x00C1 },
+	{ 0x00E2, 0x00C2 },
+	{ 0x00E3, 0x00C3 },
+	{ 0x00E4, 0x00C4 },
+	{ 0x00E5, 0x00C5 },
+	{ 0x00E6, 0x00C6 },
+	{ 0x00E7, 0x00C7 },
+	{ 0x00E8, 0x00C8 },
+	{ 0x00E9, 0x00C9 },
+	{ 0x00EA, 0x00CA },
+	{ 0x00EB, 0x00CB },
+	{ 0x00EC, 0x00CC },
+	{ 0x00ED, 0x00CD },
+	{ 0x00EE, 0x00CE },
+	{ 0x00EF, 0x00CF },
+	{ 0x00F0, 0x00D0 },
+	{ 0x00F1, 0x00D1 },
+	{ 0x00F2, 0x00D2 },
+	{ 0x00F3, 0x00D3 },
+	{ 0x00F4, 0x00D4 },
+	{ 0x00F5, 0x00D5 },
+	{ 0x00F6, 0x00D6 },
+	{ 0x00F8, 0x00D8 },
+	{ 0x00F9, 0x00D9 },
+	{ 0x00FA, 0x00DA },
+	{ 0x00FB, 0x00DB },
+	{ 0x00FC, 0x00DC },
+	{ 0x00FD, 0x00DD },
+	{ 0x00FE, 0x00DE },
+	{ 0x00FF, 0x0178 },
+	{ 0x0101, 0x0100 },
+	{ 0x0103, 0x0102 },
+	{ 0x0105, 0x0104 },
+	{ 0x0107, 0x0106 },
+	{ 0x0109, 0x0108 },
+	{ 0x010B, 0x010A },
+	{ 0x010D, 0x010C },
+	{ 0x010F, 0x010E },
+	{ 0x0111, 0x0110 },
+	{ 0x0113, 0x0112 },
+	{ 0x0115, 0x0114 },
+	{ 0x0117, 0x0116 },
+	{ 0x0119, 0x0118 },
+	{ 0x011B, 0x011A },
+	{ 0x011D, 0x011C },
+	{ 0x011F, 0x011E },
+	{ 0x0121, 0x0120 },
+	{ 0x0123, 0x0122 },
+	{ 0x0125, 0x0124 },
+	{ 0x0127, 0x0126 },
+	{ 0x0129, 0x0128 },
+	{ 0x012B, 0x012A },
+	{ 0x012D, 0x012C },
+	{ 0x012F, 0x012E },
+	{ 0x0131, 0x0049 },
+	{ 0x0133, 0x0132 },
+	{ 0x0135, 0x0134 },
+	{ 0x0137, 0x0136 },
+	{ 0x013A, 0x0139 },
+	{ 0x013C, 0x013B },
+	{ 0x013E, 0x013D },
+	{ 0x0140, 0x013F },
+	{ 0x0142, 0x0141 },
+	{ 0x0144, 0x0143 },
+	{ 0x0146, 0x0145 },
+	{ 0x0148, 0x0147 },
+	{ 0x014B, 0x014A },
+	{ 0x014D, 0x014C },
+	{ 0x014F, 0x014E },
+	{ 0x0151, 0x0150 },
+	{ 0x0153, 0x0152 },
+	{ 0x0155, 0x0154 },
+	{ 0x0157, 0x0156 },
+	{ 0x0159, 0x0158 },
+	{ 0x015B, 0x015A },
+	{ 0x015D, 0x015C },
+	{ 0x015F, 0x015E },
+	{ 0x0161, 0x0160 },
+	{ 0x0163, 0x0162 },
+	{ 0x0165, 0x0164 },
+	{ 0x0167, 0x0166 },
+	{ 0x0169, 0x0168 },
+	{ 0x016B, 0x016A },
+	{ 0x016D, 0x016C },
+	{ 0x016F, 0x016E },
+	{ 0x0171, 0x0170 },
+	{ 0x0173, 0x0172 },
+	{ 0x0175, 0x0174 },
+	{ 0x0177, 0x0176 },
+	{ 0x017A, 0x0179 },
+	{ 0x017C, 0x017B },
+	{ 0x017E, 0x017D },
+	{ 0x0183, 0x0182 },
+	{ 0x0185, 0x0184 },
+	{ 0x0188, 0x0187 },
+	{ 0x018C, 0x018B },
+	{ 0x0192, 0x0191 },
+	{ 0x0199, 0x0198 },
+	{ 0x01A1, 0x01A0 },
+	{ 0x01A3, 0x01A2 },
+	{ 0x01A5, 0x01A4 },
+	{ 0x01A8, 0x01A7 },
+	{ 0x01AD, 0x01AC },
+	{ 0x01B0, 0x01AF },
+	{ 0x01B4, 0x01B3 },
+	{ 0x01B6, 0x01B5 },
+	{ 0x01B9, 0x01B8 },
+	{ 0x01BD, 0x01BC },
+	{ 0x01C6, 0x01C4 },
+	{ 0x01C9, 0x01C7 },
+	{ 0x01CC, 0x01CA },
+	{ 0x01CE, 0x01CD },
+	{ 0x01D0, 0x01CF },
+	{ 0x01D2, 0x01D1 },
+	{ 0x01D4, 0x01D3 },
+	{ 0x01D6, 0x01D5 },
+	{ 0x01D8, 0x01D7 },
+	{ 0x01DA, 0x01D9 },
+	{ 0x01DC, 0x01DB },
+	{ 0x01DF, 0x01DE },
+	{ 0x01E1, 0x01E0 },
+	{ 0x01E3, 0x01E2 },
+	{ 0x01E5, 0x01E4 },
+	{ 0x01E7, 0x01E6 },
+	{ 0x01E9, 0x01E8 },
+	{ 0x01EB, 0x01EA },
+	{ 0x01ED, 0x01EC },
+	{ 0x01EF, 0x01EE },
+	{ 0x01F3, 0x01F1 },
+	{ 0x01F5, 0x01F4 },
+	{ 0x01FB, 0x01FA },
+	{ 0x01FD, 0x01FC },
+	{ 0x01FF, 0x01FE },
+	{ 0x0201, 0x0200 },
+	{ 0x0203, 0x0202 },
+	{ 0x0205, 0x0204 },
+	{ 0x0207, 0x0206 },
+	{ 0x0209, 0x0208 },
+	{ 0x020B, 0x020A },
+	{ 0x020D, 0x020C },
+	{ 0x020F, 0x020E },
+	{ 0x0211, 0x0210 },
+	{ 0x0213, 0x0212 },
+	{ 0x0215, 0x0214 },
+	{ 0x0217, 0x0216 },
+	{ 0x0253, 0x0181 },
+	{ 0x0254, 0x0186 },
+	{ 0x0257, 0x018A },
+	{ 0x0258, 0x018E },
+	{ 0x0259, 0x018F },
+	{ 0x025B, 0x0190 },
+	{ 0x0260, 0x0193 },
+	{ 0x0263, 0x0194 },
+	{ 0x0268, 0x0197 },
+	{ 0x0269, 0x0196 },
+	{ 0x026F, 0x019C },
+	{ 0x0272, 0x019D },
+	{ 0x0275, 0x019F },
+	{ 0x0283, 0x01A9 },
+	{ 0x0288, 0x01AE },
+	{ 0x028A, 0x01B1 },
+	{ 0x028B, 0x01B2 },
+	{ 0x0292, 0x01B7 },
+	{ 0x03AC, 0x0386 },
+	{ 0x03AD, 0x0388 },
+	{ 0x03AE, 0x0389 },
+	{ 0x03AF, 0x038A },
+	{ 0x03B1, 0x0391 },
+	{ 0x03B2, 0x0392 },
+	{ 0x03B3, 0x0393 },
+	{ 0x03B4, 0x0394 },
+	{ 0x03B5, 0x0395 },
+	{ 0x03B6, 0x0396 },
+	{ 0x03B7, 0x0397 },
+	{ 0x03B8, 0x0398 },
+	{ 0x03B9, 0x0399 },
+	{ 0x03BA, 0x039A },
+	{ 0x03BB, 0x039B },
+	{ 0x03BC, 0x039C },
+	{ 0x03BD, 0x039D },
+	{ 0x03BE, 0x039E },
+	{ 0x03BF, 0x039F },
+	{ 0x03C0, 0x03A0 },
+	{ 0x03C1, 0x03A1 },
+	{ 0x03C3, 0x03A3 },
+	{ 0x03C4, 0x03A4 },
+	{ 0x03C5, 0x03A5 },
+	{ 0x03C6, 0x03A6 },
+	{ 0x03C7, 0x03A7 },
+	{ 0x03C8, 0x03A8 },
+	{ 0x03C9, 0x03A9 },
+	{ 0x03CA, 0x03AA },
+	{ 0x03CB, 0x03AB },
+	{ 0x03CC, 0x038C },
+	{ 0x03CD, 0x038E },
+	{ 0x03CE, 0x038F },
+	{ 0x03E3, 0x03E2 },
+	{ 0x03E5, 0x03E4 },
+	{ 0x03E7, 0x03E6 },
+	{ 0x03E9, 0x03E8 },
+	{ 0x03EB, 0x03EA },
+	{ 0x03ED, 0x03EC },
+	{ 0x03EF, 0x03EE },
+	{ 0x0430, 0x0410 },
+	{ 0x0431, 0x0411 },
+	{ 0x0432, 0x0412 },
+	{ 0x0433, 0x0413 },
+	{ 0x0434, 0x0414 },
+	{ 0x0435, 0x0415 },
+	{ 0x0436, 0x0416 },
+	{ 0x0437, 0x0417 },
+	{ 0x0438, 0x0418 },
+	{ 0x0439, 0x0419 },
+	{ 0x043A, 0x041A },
+	{ 0x043B, 0x041B },
+	{ 0x043C, 0x041C },
+	{ 0x043D, 0x041D },
+	{ 0x043E, 0x041E },
+	{ 0x043F, 0x041F },
+	{ 0x0440, 0x0420 },
+	{ 0x0441, 0x0421 },
+	{ 0x0442, 0x0422 },
+	{ 0x0443, 0x0423 },
+	{ 0x0444, 0x0424 },
+	{ 0x0445, 0x0425 },
+	{ 0x0446, 0x0426 },
+	{ 0x0447, 0x0427 },
+	{ 0x0448, 0x0428 },
+	{ 0x0449, 0x0429 },
+	{ 0x044A, 0x042A },
+	{ 0x044B, 0x042B },
+	{ 0x044C, 0x042C },
+	{ 0x044D, 0x042D },
+	{ 0x044E, 0x042E },
+	{ 0x044F, 0x042F },
+	{ 0x0451, 0x0401 },
+	{ 0x0452, 0x0402 },
+	{ 0x0453, 0x0403 },
+	{ 0x0454, 0x0404 },
+	{ 0x0455, 0x0405 },
+	{ 0x0456, 0x0406 },
+	{ 0x0457, 0x0407 },
+	{ 0x0458, 0x0408 },
+	{ 0x0459, 0x0409 },
+	{ 0x045A, 0x040A },
+	{ 0x045B, 0x040B },
+	{ 0x045C, 0x040C },
+	{ 0x045E, 0x040E },
+	{ 0x045F, 0x040F },
+	{ 0x0461, 0x0460 },
+	{ 0x0463, 0x0462 },
+	{ 0x0465, 0x0464 },
+	{ 0x0467, 0x0466 },
+	{ 0x0469, 0x0468 },
+	{ 0x046B, 0x046A },
+	{ 0x046D, 0x046C },
+	{ 0x046F, 0x046E },
+	{ 0x0471, 0x0470 },
+	{ 0x0473, 0x0472 },
+	{ 0x0475, 0x0474 },
+	{ 0x0477, 0x0476 },
+	{ 0x0479, 0x0478 },
+	{ 0x047B, 0x047A },
+	{ 0x047D, 0x047C },
+	{ 0x047F, 0x047E },
+	{ 0x0481, 0x0480 },
+	{ 0x0491, 0x0490 },
+	{ 0x0493, 0x0492 },
+	{ 0x0495, 0x0494 },
+	{ 0x0497, 0x0496 },
+	{ 0x0499, 0x0498 },
+	{ 0x049B, 0x049A },
+	{ 0x049D, 0x049C },
+	{ 0x049F, 0x049E },
+	{ 0x04A1, 0x04A0 },
+	{ 0x04A3, 0x04A2 },
+	{ 0x04A5, 0x04A4 },
+	{ 0x04A7, 0x04A6 },
+	{ 0x04A9, 0x04A8 },
+	{ 0x04AB, 0x04AA },
+	{ 0x04AD, 0x04AC },
+	{ 0x04AF, 0x04AE },
+	{ 0x04B1, 0x04B0 },
+	{ 0x04B3, 0x04B2 },
+	{ 0x04B5, 0x04B4 },
+	{ 0x04B7, 0x04B6 },
+	{ 0x04B9, 0x04B8 },
+	{ 0x04BB, 0x04BA },
+	{ 0x04BD, 0x04BC },
+	{ 0x04BF, 0x04BE },
+	{ 0x04C2, 0x04C1 },
+	{ 0x04C4, 0x04C3 },
+	{ 0x04C8, 0x04C7 },
+	{ 0x04CC, 0x04CB },
+	{ 0x04D1, 0x04D0 },
+	{ 0x04D3, 0x04D2 },
+	{ 0x04D5, 0x04D4 },
+	{ 0x04D7, 0x04D6 },
+	{ 0x04D9, 0x04D8 },
+	{ 0x04DB, 0x04DA },
+	{ 0x04DD, 0x04DC },
+	{ 0x04DF, 0x04DE },
+	{ 0x04E1, 0x04E0 },
+	{ 0x04E3, 0x04E2 },
+	{ 0x04E5, 0x04E4 },
+	{ 0x04E7, 0x04E6 },
+	{ 0x04E9, 0x04E8 },
+	{ 0x04EB, 0x04EA },
+	{ 0x04EF, 0x04EE },
+	{ 0x04F1, 0x04F0 },
+	{ 0x04F3, 0x04F2 },
+	{ 0x04F5, 0x04F4 },
+	{ 0x04F9, 0x04F8 },
+	{ 0x0561, 0x0531 },
+	{ 0x0562, 0x0532 },
+	{ 0x0563, 0x0533 },
+	{ 0x0564, 0x0534 },
+	{ 0x0565, 0x0535 },
+	{ 0x0566, 0x0536 },
+	{ 0x0567, 0x0537 },
+	{ 0x0568, 0x0538 },
+	{ 0x0569, 0x0539 },
+	{ 0x056A, 0x053A },
+	{ 0x056B, 0x053B },
+	{ 0x056C, 0x053C },
+	{ 0x056D, 0x053D },
+	{ 0x056E, 0x053E },
+	{ 0x056F, 0x053F },
+	{ 0x0570, 0x0540 },
+	{ 0x0571, 0x0541 },
+	{ 0x0572, 0x0542 },
+	{ 0x0573, 0x0543 },
+	{ 0x0574, 0x0544 },
+	{ 0x0575, 0x0545 },
+	{ 0x0576, 0x0546 },
+	{ 0x0577, 0x0547 },
+	{ 0x0578, 0x0548 },
+	{ 0x0579, 0x0549 },
+	{ 0x057A, 0x054A },
+	{ 0x057B, 0x054B },
+	{ 0x057C, 0x054C },
+	{ 0x057D, 0x054D },
+	{ 0x057E, 0x054E },
+	{ 0x057F, 0x054F },
+	{ 0x0580, 0x0550 },
+	{ 0x0581, 0x0551 },
+	{ 0x0582, 0x0552 },
+	{ 0x0583, 0x0553 },
+	{ 0x0584, 0x0554 },
+	{ 0x0585, 0x0555 },
+	{ 0x0586, 0x0556 },
+	{ 0x10D0, 0x10A0 },
+	{ 0x10D1, 0x10A1 },
+	{ 0x10D2, 0x10A2 },
+	{ 0x10D3, 0x10A3 },
+	{ 0x10D4, 0x10A4 },
+	{ 0x10D5, 0x10A5 },
+	{ 0x10D6, 0x10A6 },
+	{ 0x10D7, 0x10A7 },
+	{ 0x10D8, 0x10A8 },
+	{ 0x10D9, 0x10A9 },
+	{ 0x10DA, 0x10AA },
+	{ 0x10DB, 0x10AB },
+	{ 0x10DC, 0x10AC },
+	{ 0x10DD, 0x10AD },
+	{ 0x10DE, 0x10AE },
+	{ 0x10DF, 0x10AF },
+	{ 0x10E0, 0x10B0 },
+	{ 0x10E1, 0x10B1 },
+	{ 0x10E2, 0x10B2 },
+	{ 0x10E3, 0x10B3 },
+	{ 0x10E4, 0x10B4 },
+	{ 0x10E5, 0x10B5 },
+	{ 0x10E6, 0x10B6 },
+	{ 0x10E7, 0x10B7 },
+	{ 0x10E8, 0x10B8 },
+	{ 0x10E9, 0x10B9 },
+	{ 0x10EA, 0x10BA },
+	{ 0x10EB, 0x10BB },
+	{ 0x10EC, 0x10BC },
+	{ 0x10ED, 0x10BD },
+	{ 0x10EE, 0x10BE },
+	{ 0x10EF, 0x10BF },
+	{ 0x10F0, 0x10C0 },
+	{ 0x10F1, 0x10C1 },
+	{ 0x10F2, 0x10C2 },
+	{ 0x10F3, 0x10C3 },
+	{ 0x10F4, 0x10C4 },
+	{ 0x10F5, 0x10C5 },
+	{ 0x1E01, 0x1E00 },
+	{ 0x1E03, 0x1E02 },
+	{ 0x1E05, 0x1E04 },
+	{ 0x1E07, 0x1E06 },
+	{ 0x1E09, 0x1E08 },
+	{ 0x1E0B, 0x1E0A },
+	{ 0x1E0D, 0x1E0C },
+	{ 0x1E0F, 0x1E0E },
+	{ 0x1E11, 0x1E10 },
+	{ 0x1E13, 0x1E12 },
+	{ 0x1E15, 0x1E14 },
+	{ 0x1E17, 0x1E16 },
+	{ 0x1E19, 0x1E18 },
+	{ 0x1E1B, 0x1E1A },
+	{ 0x1E1D, 0x1E1C },
+	{ 0x1E1F, 0x1E1E },
+	{ 0x1E21, 0x1E20 },
+	{ 0x1E23, 0x1E22 },
+	{ 0x1E25, 0x1E24 },
+	{ 0x1E27, 0x1E26 },
+	{ 0x1E29, 0x1E28 },
+	{ 0x1E2B, 0x1E2A },
+	{ 0x1E2D, 0x1E2C },
+	{ 0x1E2F, 0x1E2E },
+	{ 0x1E31, 0x1E30 },
+	{ 0x1E33, 0x1E32 },
+	{ 0x1E35, 0x1E34 },
+	{ 0x1E37, 0x1E36 },
+	{ 0x1E39, 0x1E38 },
+	{ 0x1E3B, 0x1E3A },
+	{ 0x1E3D, 0x1E3C },
+	{ 0x1E3F, 0x1E3E },
+	{ 0x1E41, 0x1E40 },
+	{ 0x1E43, 0x1E42 },
+	{ 0x1E45, 0x1E44 },
+	{ 0x1E47, 0x1E46 },
+	{ 0x1E49, 0x1E48 },
+	{ 0x1E4B, 0x1E4A },
+	{ 0x1E4D, 0x1E4C },
+	{ 0x1E4F, 0x1E4E },
+	{ 0x1E51, 0x1E50 },
+	{ 0x1E53, 0x1E52 },
+	{ 0x1E55, 0x1E54 },
+	{ 0x1E57, 0x1E56 },
+	{ 0x1E59, 0x1E58 },
+	{ 0x1E5B, 0x1E5A },
+	{ 0x1E5D, 0x1E5C },
+	{ 0x1E5F, 0x1E5E },
+	{ 0x1E61, 0x1E60 },
+	{ 0x1E63, 0x1E62 },
+	{ 0x1E65, 0x1E64 },
+	{ 0x1E67, 0x1E66 },
+	{ 0x1E69, 0x1E68 },
+	{ 0x1E6B, 0x1E6A },
+	{ 0x1E6D, 0x1E6C },
+	{ 0x1E6F, 0x1E6E },
+	{ 0x1E71, 0x1E70 },
+	{ 0x1E73, 0x1E72 },
+	{ 0x1E75, 0x1E74 },
+	{ 0x1E77, 0x1E76 },
+	{ 0x1E79, 0x1E78 },
+	{ 0x1E7B, 0x1E7A },
+	{ 0x1E7D, 0x1E7C },
+	{ 0x1E7F, 0x1E7E },
+	{ 0x1E81, 0x1E80 },
+	{ 0x1E83, 0x1E82 },
+	{ 0x1E85, 0x1E84 },
+	{ 0x1E87, 0x1E86 },
+	{ 0x1E89, 0x1E88 },
+	{ 0x1E8B, 0x1E8A },
+	{ 0x1E8D, 0x1E8C },
+	{ 0x1E8F, 0x1E8E },
+	{ 0x1E91, 0x1E90 },
+	{ 0x1E93, 0x1E92 },
+	{ 0x1E95, 0x1E94 },
+	{ 0x1EA1, 0x1EA0 },
+	{ 0x1EA3, 0x1EA2 },
+	{ 0x1EA5, 0x1EA4 },
+	{ 0x1EA7, 0x1EA6 },
+	{ 0x1EA9, 0x1EA8 },
+	{ 0x1EAB, 0x1EAA },
+	{ 0x1EAD, 0x1EAC },
+	{ 0x1EAF, 0x1EAE },
+	{ 0x1EB1, 0x1EB0 },
+	{ 0x1EB3, 0x1EB2 },
+	{ 0x1EB5, 0x1EB4 },
+	{ 0x1EB7, 0x1EB6 },
+	{ 0x1EB9, 0x1EB8 },
+	{ 0x1EBB, 0x1EBA },
+	{ 0x1EBD, 0x1EBC },
+	{ 0x1EBF, 0x1EBE },
+	{ 0x1EC1, 0x1EC0 },
+	{ 0x1EC3, 0x1EC2 },
+	{ 0x1EC5, 0x1EC4 },
+	{ 0x1EC7, 0x1EC6 },
+	{ 0x1EC9, 0x1EC8 },
+	{ 0x1ECB, 0x1ECA },
+	{ 0x1ECD, 0x1ECC },
+	{ 0x1ECF, 0x1ECE },
+	{ 0x1ED1, 0x1ED0 },
+	{ 0x1ED3, 0x1ED2 },
+	{ 0x1ED5, 0x1ED4 },
+	{ 0x1ED7, 0x1ED6 },
+	{ 0x1ED9, 0x1ED8 },
+	{ 0x1EDB, 0x1EDA },
+	{ 0x1EDD, 0x1EDC },
+	{ 0x1EDF, 0x1EDE },
+	{ 0x1EE1, 0x1EE0 },
+	{ 0x1EE3, 0x1EE2 },
+	{ 0x1EE5, 0x1EE4 },
+	{ 0x1EE7, 0x1EE6 },
+	{ 0x1EE9, 0x1EE8 },
+	{ 0x1EEB, 0x1EEA },
+	{ 0x1EED, 0x1EEC },
+	{ 0x1EEF, 0x1EEE },
+	{ 0x1EF1, 0x1EF0 },
+	{ 0x1EF3, 0x1EF2 },
+	{ 0x1EF5, 0x1EF4 },
+	{ 0x1EF7, 0x1EF6 },
+	{ 0x1EF9, 0x1EF8 },
+	{ 0x1F00, 0x1F08 },
+	{ 0x1F01, 0x1F09 },
+	{ 0x1F02, 0x1F0A },
+	{ 0x1F03, 0x1F0B },
+	{ 0x1F04, 0x1F0C },
+	{ 0x1F05, 0x1F0D },
+	{ 0x1F06, 0x1F0E },
+	{ 0x1F07, 0x1F0F },
+	{ 0x1F10, 0x1F18 },
+	{ 0x1F11, 0x1F19 },
+	{ 0x1F12, 0x1F1A },
+	{ 0x1F13, 0x1F1B },
+	{ 0x1F14, 0x1F1C },
+	{ 0x1F15, 0x1F1D },
+	{ 0x1F20, 0x1F28 },
+	{ 0x1F21, 0x1F29 },
+	{ 0x1F22, 0x1F2A },
+	{ 0x1F23, 0x1F2B },
+	{ 0x1F24, 0x1F2C },
+	{ 0x1F25, 0x1F2D },
+	{ 0x1F26, 0x1F2E },
+	{ 0x1F27, 0x1F2F },
+	{ 0x1F30, 0x1F38 },
+	{ 0x1F31, 0x1F39 },
+	{ 0x1F32, 0x1F3A },
+	{ 0x1F33, 0x1F3B },
+	{ 0x1F34, 0x1F3C },
+	{ 0x1F35, 0x1F3D },
+	{ 0x1F36, 0x1F3E },
+	{ 0x1F37, 0x1F3F },
+	{ 0x1F40, 0x1F48 },
+	{ 0x1F41, 0x1F49 },
+	{ 0x1F42, 0x1F4A },
+	{ 0x1F43, 0x1F4B },
+	{ 0x1F44, 0x1F4C },
+	{ 0x1F45, 0x1F4D },
+	{ 0x1F51, 0x1F59 },
+	{ 0x1F53, 0x1F5B },
+	{ 0x1F55, 0x1F5D },
+	{ 0x1F57, 0x1F5F },
+	{ 0x1F60, 0x1F68 },
+	{ 0x1F61, 0x1F69 },
+	{ 0x1F62, 0x1F6A },
+	{ 0x1F63, 0x1F6B },
+	{ 0x1F64, 0x1F6C },
+	{ 0x1F65, 0x1F6D },
+	{ 0x1F66, 0x1F6E },
+	{ 0x1F67, 0x1F6F },
+	{ 0x1F80, 0x1F88 },
+	{ 0x1F81, 0x1F89 },
+	{ 0x1F82, 0x1F8A },
+	{ 0x1F83, 0x1F8B },
+	{ 0x1F84, 0x1F8C },
+	{ 0x1F85, 0x1F8D },
+	{ 0x1F86, 0x1F8E },
+	{ 0x1F87, 0x1F8F },
+	{ 0x1F90, 0x1F98 },
+	{ 0x1F91, 0x1F99 },
+	{ 0x1F92, 0x1F9A },
+	{ 0x1F93, 0x1F9B },
+	{ 0x1F94, 0x1F9C },
+	{ 0x1F95, 0x1F9D },
+	{ 0x1F96, 0x1F9E },
+	{ 0x1F97, 0x1F9F },
+	{ 0x1FA0, 0x1FA8 },
+	{ 0x1FA1, 0x1FA9 },
+	{ 0x1FA2, 0x1FAA },
+	{ 0x1FA3, 0x1FAB },
+	{ 0x1FA4, 0x1FAC },
+	{ 0x1FA5, 0x1FAD },
+	{ 0x1FA6, 0x1FAE },
+	{ 0x1FA7, 0x1FAF },
+	{ 0x1FB0, 0x1FB8 },
+	{ 0x1FB1, 0x1FB9 },
+	{ 0x1FD0, 0x1FD8 },
+	{ 0x1FD1, 0x1FD9 },
+	{ 0x1FE0, 0x1FE8 },
+	{ 0x1FE1, 0x1FE9 },
+	{ 0x24D0, 0x24B6 },
+	{ 0x24D1, 0x24B7 },
+	{ 0x24D2, 0x24B8 },
+	{ 0x24D3, 0x24B9 },
+	{ 0x24D4, 0x24BA },
+	{ 0x24D5, 0x24BB },
+	{ 0x24D6, 0x24BC },
+	{ 0x24D7, 0x24BD },
+	{ 0x24D8, 0x24BE },
+	{ 0x24D9, 0x24BF },
+	{ 0x24DA, 0x24C0 },
+	{ 0x24DB, 0x24C1 },
+	{ 0x24DC, 0x24C2 },
+	{ 0x24DD, 0x24C3 },
+	{ 0x24DE, 0x24C4 },
+	{ 0x24DF, 0x24C5 },
+	{ 0x24E0, 0x24C6 },
+	{ 0x24E1, 0x24C7 },
+	{ 0x24E2, 0x24C8 },
+	{ 0x24E3, 0x24C9 },
+	{ 0x24E4, 0x24CA },
+	{ 0x24E5, 0x24CB },
+	{ 0x24E6, 0x24CC },
+	{ 0x24E7, 0x24CD },
+	{ 0x24E8, 0x24CE },
+	{ 0x24E9, 0x24CF },
+	{ 0xFF41, 0xFF21 },
+	{ 0xFF42, 0xFF22 },
+	{ 0xFF43, 0xFF23 },
+	{ 0xFF44, 0xFF24 },
+	{ 0xFF45, 0xFF25 },
+	{ 0xFF46, 0xFF26 },
+	{ 0xFF47, 0xFF27 },
+	{ 0xFF48, 0xFF28 },
+	{ 0xFF49, 0xFF29 },
+	{ 0xFF4A, 0xFF2A },
+	{ 0xFF4B, 0xFF2B },
+	{ 0xFF4C, 0xFF2C },
+	{ 0xFF4D, 0xFF2D },
+	{ 0xFF4E, 0xFF2E },
+	{ 0xFF4F, 0xFF2F },
+	{ 0xFF50, 0xFF30 },
+	{ 0xFF51, 0xFF31 },
+	{ 0xFF52, 0xFF32 },
+	{ 0xFF53, 0xFF33 },
+	{ 0xFF54, 0xFF34 },
+	{ 0xFF55, 0xFF35 },
+	{ 0xFF56, 0xFF36 },
+	{ 0xFF57, 0xFF37 },
+	{ 0xFF58, 0xFF38 },
+	{ 0xFF59, 0xFF39 },
+	{ 0xFF5A, 0xFF3A },
+};
+
+static const int reverse_caps_table[CAPS_LEN - 1][2] = {
+	{ 0x0041, 0x0061 },
+	{ 0x0042, 0x0062 },
+	{ 0x0043, 0x0063 },
+	{ 0x0044, 0x0064 },
+	{ 0x0045, 0x0065 },
+	{ 0x0046, 0x0066 },
+	{ 0x0047, 0x0067 },
+	{ 0x0048, 0x0068 },
+	{ 0x0049, 0x0069 },
+	// { 0x0049, 0x0131 }, // dotless I
+	{ 0x004A, 0x006A },
+	{ 0x004B, 0x006B },
+	{ 0x004C, 0x006C },
+	{ 0x004D, 0x006D },
+	{ 0x004E, 0x006E },
+	{ 0x004F, 0x006F },
+	{ 0x0050, 0x0070 },
+	{ 0x0051, 0x0071 },
+	{ 0x0052, 0x0072 },
+	{ 0x0053, 0x0073 },
+	{ 0x0054, 0x0074 },
+	{ 0x0055, 0x0075 },
+	{ 0x0056, 0x0076 },
+	{ 0x0057, 0x0077 },
+	{ 0x0058, 0x0078 },
+	{ 0x0059, 0x0079 },
+	{ 0x005A, 0x007A },
+	{ 0x00C0, 0x00E0 },
+	{ 0x00C1, 0x00E1 },
+	{ 0x00C2, 0x00E2 },
+	{ 0x00C3, 0x00E3 },
+	{ 0x00C4, 0x00E4 },
+	{ 0x00C5, 0x00E5 },
+	{ 0x00C6, 0x00E6 },
+	{ 0x00C7, 0x00E7 },
+	{ 0x00C8, 0x00E8 },
+	{ 0x00C9, 0x00E9 },
+	{ 0x00CA, 0x00EA },
+	{ 0x00CB, 0x00EB },
+	{ 0x00CC, 0x00EC },
+	{ 0x00CD, 0x00ED },
+	{ 0x00CE, 0x00EE },
+	{ 0x00CF, 0x00EF },
+	{ 0x00D0, 0x00F0 },
+	{ 0x00D1, 0x00F1 },
+	{ 0x00D2, 0x00F2 },
+	{ 0x00D3, 0x00F3 },
+	{ 0x00D4, 0x00F4 },
+	{ 0x00D5, 0x00F5 },
+	{ 0x00D6, 0x00F6 },
+	{ 0x00D8, 0x00F8 },
+	{ 0x00D9, 0x00F9 },
+	{ 0x00DA, 0x00FA },
+	{ 0x00DB, 0x00FB },
+	{ 0x00DC, 0x00FC },
+	{ 0x00DD, 0x00FD },
+	{ 0x00DE, 0x00FE },
+	{ 0x0100, 0x0101 },
+	{ 0x0102, 0x0103 },
+	{ 0x0104, 0x0105 },
+	{ 0x0106, 0x0107 },
+	{ 0x0108, 0x0109 },
+	{ 0x010A, 0x010B },
+	{ 0x010C, 0x010D },
+	{ 0x010E, 0x010F },
+	{ 0x0110, 0x0111 },
+	{ 0x0112, 0x0113 },
+	{ 0x0114, 0x0115 },
+	{ 0x0116, 0x0117 },
+	{ 0x0118, 0x0119 },
+	{ 0x011A, 0x011B },
+	{ 0x011C, 0x011D },
+	{ 0x011E, 0x011F },
+	{ 0x0120, 0x0121 },
+	{ 0x0122, 0x0123 },
+	{ 0x0124, 0x0125 },
+	{ 0x0126, 0x0127 },
+	{ 0x0128, 0x0129 },
+	{ 0x012A, 0x012B },
+	{ 0x012C, 0x012D },
+	{ 0x012E, 0x012F },
+	{ 0x0132, 0x0133 },
+	{ 0x0134, 0x0135 },
+	{ 0x0136, 0x0137 },
+	{ 0x0139, 0x013A },
+	{ 0x013B, 0x013C },
+	{ 0x013D, 0x013E },
+	{ 0x013F, 0x0140 },
+	{ 0x0141, 0x0142 },
+	{ 0x0143, 0x0144 },
+	{ 0x0145, 0x0146 },
+	{ 0x0147, 0x0148 },
+	{ 0x014A, 0x014B },
+	{ 0x014C, 0x014D },
+	{ 0x014E, 0x014F },
+	{ 0x0150, 0x0151 },
+	{ 0x0152, 0x0153 },
+	{ 0x0154, 0x0155 },
+	{ 0x0156, 0x0157 },
+	{ 0x0158, 0x0159 },
+	{ 0x015A, 0x015B },
+	{ 0x015C, 0x015D },
+	{ 0x015E, 0x015F },
+	{ 0x0160, 0x0161 },
+	{ 0x0162, 0x0163 },
+	{ 0x0164, 0x0165 },
+	{ 0x0166, 0x0167 },
+	{ 0x0168, 0x0169 },
+	{ 0x016A, 0x016B },
+	{ 0x016C, 0x016D },
+	{ 0x016E, 0x016F },
+	{ 0x0170, 0x0171 },
+	{ 0x0172, 0x0173 },
+	{ 0x0174, 0x0175 },
+	{ 0x0176, 0x0177 },
+	{ 0x0178, 0x00FF },
+	{ 0x0179, 0x017A },
+	{ 0x017B, 0x017C },
+	{ 0x017D, 0x017E },
+	{ 0x0181, 0x0253 },
+	{ 0x0182, 0x0183 },
+	{ 0x0184, 0x0185 },
+	{ 0x0186, 0x0254 },
+	{ 0x0187, 0x0188 },
+	{ 0x018A, 0x0257 },
+	{ 0x018B, 0x018C },
+	{ 0x018E, 0x0258 },
+	{ 0x018F, 0x0259 },
+	{ 0x0190, 0x025B },
+	{ 0x0191, 0x0192 },
+	{ 0x0193, 0x0260 },
+	{ 0x0194, 0x0263 },
+	{ 0x0196, 0x0269 },
+	{ 0x0197, 0x0268 },
+	{ 0x0198, 0x0199 },
+	{ 0x019C, 0x026F },
+	{ 0x019D, 0x0272 },
+	{ 0x019F, 0x0275 },
+	{ 0x01A0, 0x01A1 },
+	{ 0x01A2, 0x01A3 },
+	{ 0x01A4, 0x01A5 },
+	{ 0x01A7, 0x01A8 },
+	{ 0x01A9, 0x0283 },
+	{ 0x01AC, 0x01AD },
+	{ 0x01AE, 0x0288 },
+	{ 0x01AF, 0x01B0 },
+	{ 0x01B1, 0x028A },
+	{ 0x01B2, 0x028B },
+	{ 0x01B3, 0x01B4 },
+	{ 0x01B5, 0x01B6 },
+	{ 0x01B7, 0x0292 },
+	{ 0x01B8, 0x01B9 },
+	{ 0x01BC, 0x01BD },
+	{ 0x01C4, 0x01C6 },
+	{ 0x01C7, 0x01C9 },
+	{ 0x01CA, 0x01CC },
+	{ 0x01CD, 0x01CE },
+	{ 0x01CF, 0x01D0 },
+	{ 0x01D1, 0x01D2 },
+	{ 0x01D3, 0x01D4 },
+	{ 0x01D5, 0x01D6 },
+	{ 0x01D7, 0x01D8 },
+	{ 0x01D9, 0x01DA },
+	{ 0x01DB, 0x01DC },
+	{ 0x01DE, 0x01DF },
+	{ 0x01E0, 0x01E1 },
+	{ 0x01E2, 0x01E3 },
+	{ 0x01E4, 0x01E5 },
+	{ 0x01E6, 0x01E7 },
+	{ 0x01E8, 0x01E9 },
+	{ 0x01EA, 0x01EB },
+	{ 0x01EC, 0x01ED },
+	{ 0x01EE, 0x01EF },
+	{ 0x01F1, 0x01F3 },
+	{ 0x01F4, 0x01F5 },
+	{ 0x01FA, 0x01FB },
+	{ 0x01FC, 0x01FD },
+	{ 0x01FE, 0x01FF },
+	{ 0x0200, 0x0201 },
+	{ 0x0202, 0x0203 },
+	{ 0x0204, 0x0205 },
+	{ 0x0206, 0x0207 },
+	{ 0x0208, 0x0209 },
+	{ 0x020A, 0x020B },
+	{ 0x020C, 0x020D },
+	{ 0x020E, 0x020F },
+	{ 0x0210, 0x0211 },
+	{ 0x0212, 0x0213 },
+	{ 0x0214, 0x0215 },
+	{ 0x0216, 0x0217 },
+	{ 0x0386, 0x03AC },
+	{ 0x0388, 0x03AD },
+	{ 0x0389, 0x03AE },
+	{ 0x038A, 0x03AF },
+	{ 0x038C, 0x03CC },
+	{ 0x038E, 0x03CD },
+	{ 0x038F, 0x03CE },
+	{ 0x0391, 0x03B1 },
+	{ 0x0392, 0x03B2 },
+	{ 0x0393, 0x03B3 },
+	{ 0x0394, 0x03B4 },
+	{ 0x0395, 0x03B5 },
+	{ 0x0396, 0x03B6 },
+	{ 0x0397, 0x03B7 },
+	{ 0x0398, 0x03B8 },
+	{ 0x0399, 0x03B9 },
+	{ 0x039A, 0x03BA },
+	{ 0x039B, 0x03BB },
+	{ 0x039C, 0x03BC },
+	{ 0x039D, 0x03BD },
+	{ 0x039E, 0x03BE },
+	{ 0x039F, 0x03BF },
+	{ 0x03A0, 0x03C0 },
+	{ 0x03A1, 0x03C1 },
+	{ 0x03A3, 0x03C3 },
+	{ 0x03A4, 0x03C4 },
+	{ 0x03A5, 0x03C5 },
+	{ 0x03A6, 0x03C6 },
+	{ 0x03A7, 0x03C7 },
+	{ 0x03A8, 0x03C8 },
+	{ 0x03A9, 0x03C9 },
+	{ 0x03AA, 0x03CA },
+	{ 0x03AB, 0x03CB },
+	{ 0x03E2, 0x03E3 },
+	{ 0x03E4, 0x03E5 },
+	{ 0x03E6, 0x03E7 },
+	{ 0x03E8, 0x03E9 },
+	{ 0x03EA, 0x03EB },
+	{ 0x03EC, 0x03ED },
+	{ 0x03EE, 0x03EF },
+	{ 0x0401, 0x0451 },
+	{ 0x0402, 0x0452 },
+	{ 0x0403, 0x0453 },
+	{ 0x0404, 0x0454 },
+	{ 0x0405, 0x0455 },
+	{ 0x0406, 0x0456 },
+	{ 0x0407, 0x0457 },
+	{ 0x0408, 0x0458 },
+	{ 0x0409, 0x0459 },
+	{ 0x040A, 0x045A },
+	{ 0x040B, 0x045B },
+	{ 0x040C, 0x045C },
+	{ 0x040E, 0x045E },
+	{ 0x040F, 0x045F },
+	{ 0x0410, 0x0430 },
+	{ 0x0411, 0x0431 },
+	{ 0x0412, 0x0432 },
+	{ 0x0413, 0x0433 },
+	{ 0x0414, 0x0434 },
+	{ 0x0415, 0x0435 },
+	{ 0x0416, 0x0436 },
+	{ 0x0417, 0x0437 },
+	{ 0x0418, 0x0438 },
+	{ 0x0419, 0x0439 },
+	{ 0x041A, 0x043A },
+	{ 0x041B, 0x043B },
+	{ 0x041C, 0x043C },
+	{ 0x041D, 0x043D },
+	{ 0x041E, 0x043E },
+	{ 0x041F, 0x043F },
+	{ 0x0420, 0x0440 },
+	{ 0x0421, 0x0441 },
+	{ 0x0422, 0x0442 },
+	{ 0x0423, 0x0443 },
+	{ 0x0424, 0x0444 },
+	{ 0x0425, 0x0445 },
+	{ 0x0426, 0x0446 },
+	{ 0x0427, 0x0447 },
+	{ 0x0428, 0x0448 },
+	{ 0x0429, 0x0449 },
+	{ 0x042A, 0x044A },
+	{ 0x042B, 0x044B },
+	{ 0x042C, 0x044C },
+	{ 0x042D, 0x044D },
+	{ 0x042E, 0x044E },
+	{ 0x042F, 0x044F },
+	{ 0x0460, 0x0461 },
+	{ 0x0462, 0x0463 },
+	{ 0x0464, 0x0465 },
+	{ 0x0466, 0x0467 },
+	{ 0x0468, 0x0469 },
+	{ 0x046A, 0x046B },
+	{ 0x046C, 0x046D },
+	{ 0x046E, 0x046F },
+	{ 0x0470, 0x0471 },
+	{ 0x0472, 0x0473 },
+	{ 0x0474, 0x0475 },
+	{ 0x0476, 0x0477 },
+	{ 0x0478, 0x0479 },
+	{ 0x047A, 0x047B },
+	{ 0x047C, 0x047D },
+	{ 0x047E, 0x047F },
+	{ 0x0480, 0x0481 },
+	{ 0x0490, 0x0491 },
+	{ 0x0492, 0x0493 },
+	{ 0x0494, 0x0495 },
+	{ 0x0496, 0x0497 },
+	{ 0x0498, 0x0499 },
+	{ 0x049A, 0x049B },
+	{ 0x049C, 0x049D },
+	{ 0x049E, 0x049F },
+	{ 0x04A0, 0x04A1 },
+	{ 0x04A2, 0x04A3 },
+	{ 0x04A4, 0x04A5 },
+	{ 0x04A6, 0x04A7 },
+	{ 0x04A8, 0x04A9 },
+	{ 0x04AA, 0x04AB },
+	{ 0x04AC, 0x04AD },
+	{ 0x04AE, 0x04AF },
+	{ 0x04B0, 0x04B1 },
+	{ 0x04B2, 0x04B3 },
+	{ 0x04B4, 0x04B5 },
+	{ 0x04B6, 0x04B7 },
+	{ 0x04B8, 0x04B9 },
+	{ 0x04BA, 0x04BB },
+	{ 0x04BC, 0x04BD },
+	{ 0x04BE, 0x04BF },
+	{ 0x04C1, 0x04C2 },
+	{ 0x04C3, 0x04C4 },
+	{ 0x04C7, 0x04C8 },
+	{ 0x04CB, 0x04CC },
+	{ 0x04D0, 0x04D1 },
+	{ 0x04D2, 0x04D3 },
+	{ 0x04D4, 0x04D5 },
+	{ 0x04D6, 0x04D7 },
+	{ 0x04D8, 0x04D9 },
+	{ 0x04DA, 0x04DB },
+	{ 0x04DC, 0x04DD },
+	{ 0x04DE, 0x04DF },
+	{ 0x04E0, 0x04E1 },
+	{ 0x04E2, 0x04E3 },
+	{ 0x04E4, 0x04E5 },
+	{ 0x04E6, 0x04E7 },
+	{ 0x04E8, 0x04E9 },
+	{ 0x04EA, 0x04EB },
+	{ 0x04EE, 0x04EF },
+	{ 0x04F0, 0x04F1 },
+	{ 0x04F2, 0x04F3 },
+	{ 0x04F4, 0x04F5 },
+	{ 0x04F8, 0x04F9 },
+	{ 0x0531, 0x0561 },
+	{ 0x0532, 0x0562 },
+	{ 0x0533, 0x0563 },
+	{ 0x0534, 0x0564 },
+	{ 0x0535, 0x0565 },
+	{ 0x0536, 0x0566 },
+	{ 0x0537, 0x0567 },
+	{ 0x0538, 0x0568 },
+	{ 0x0539, 0x0569 },
+	{ 0x053A, 0x056A },
+	{ 0x053B, 0x056B },
+	{ 0x053C, 0x056C },
+	{ 0x053D, 0x056D },
+	{ 0x053E, 0x056E },
+	{ 0x053F, 0x056F },
+	{ 0x0540, 0x0570 },
+	{ 0x0541, 0x0571 },
+	{ 0x0542, 0x0572 },
+	{ 0x0543, 0x0573 },
+	{ 0x0544, 0x0574 },
+	{ 0x0545, 0x0575 },
+	{ 0x0546, 0x0576 },
+	{ 0x0547, 0x0577 },
+	{ 0x0548, 0x0578 },
+	{ 0x0549, 0x0579 },
+	{ 0x054A, 0x057A },
+	{ 0x054B, 0x057B },
+	{ 0x054C, 0x057C },
+	{ 0x054D, 0x057D },
+	{ 0x054E, 0x057E },
+	{ 0x054F, 0x057F },
+	{ 0x0550, 0x0580 },
+	{ 0x0551, 0x0581 },
+	{ 0x0552, 0x0582 },
+	{ 0x0553, 0x0583 },
+	{ 0x0554, 0x0584 },
+	{ 0x0555, 0x0585 },
+	{ 0x0556, 0x0586 },
+	{ 0x10A0, 0x10D0 },
+	{ 0x10A1, 0x10D1 },
+	{ 0x10A2, 0x10D2 },
+	{ 0x10A3, 0x10D3 },
+	{ 0x10A4, 0x10D4 },
+	{ 0x10A5, 0x10D5 },
+	{ 0x10A6, 0x10D6 },
+	{ 0x10A7, 0x10D7 },
+	{ 0x10A8, 0x10D8 },
+	{ 0x10A9, 0x10D9 },
+	{ 0x10AA, 0x10DA },
+	{ 0x10AB, 0x10DB },
+	{ 0x10AC, 0x10DC },
+	{ 0x10AD, 0x10DD },
+	{ 0x10AE, 0x10DE },
+	{ 0x10AF, 0x10DF },
+	{ 0x10B0, 0x10E0 },
+	{ 0x10B1, 0x10E1 },
+	{ 0x10B2, 0x10E2 },
+	{ 0x10B3, 0x10E3 },
+	{ 0x10B4, 0x10E4 },
+	{ 0x10B5, 0x10E5 },
+	{ 0x10B6, 0x10E6 },
+	{ 0x10B7, 0x10E7 },
+	{ 0x10B8, 0x10E8 },
+	{ 0x10B9, 0x10E9 },
+	{ 0x10BA, 0x10EA },
+	{ 0x10BB, 0x10EB },
+	{ 0x10BC, 0x10EC },
+	{ 0x10BD, 0x10ED },
+	{ 0x10BE, 0x10EE },
+	{ 0x10BF, 0x10EF },
+	{ 0x10C0, 0x10F0 },
+	{ 0x10C1, 0x10F1 },
+	{ 0x10C2, 0x10F2 },
+	{ 0x10C3, 0x10F3 },
+	{ 0x10C4, 0x10F4 },
+	{ 0x10C5, 0x10F5 },
+	{ 0x1E00, 0x1E01 },
+	{ 0x1E02, 0x1E03 },
+	{ 0x1E04, 0x1E05 },
+	{ 0x1E06, 0x1E07 },
+	{ 0x1E08, 0x1E09 },
+	{ 0x1E0A, 0x1E0B },
+	{ 0x1E0C, 0x1E0D },
+	{ 0x1E0E, 0x1E0F },
+	{ 0x1E10, 0x1E11 },
+	{ 0x1E12, 0x1E13 },
+	{ 0x1E14, 0x1E15 },
+	{ 0x1E16, 0x1E17 },
+	{ 0x1E18, 0x1E19 },
+	{ 0x1E1A, 0x1E1B },
+	{ 0x1E1C, 0x1E1D },
+	{ 0x1E1E, 0x1E1F },
+	{ 0x1E20, 0x1E21 },
+	{ 0x1E22, 0x1E23 },
+	{ 0x1E24, 0x1E25 },
+	{ 0x1E26, 0x1E27 },
+	{ 0x1E28, 0x1E29 },
+	{ 0x1E2A, 0x1E2B },
+	{ 0x1E2C, 0x1E2D },
+	{ 0x1E2E, 0x1E2F },
+	{ 0x1E30, 0x1E31 },
+	{ 0x1E32, 0x1E33 },
+	{ 0x1E34, 0x1E35 },
+	{ 0x1E36, 0x1E37 },
+	{ 0x1E38, 0x1E39 },
+	{ 0x1E3A, 0x1E3B },
+	{ 0x1E3C, 0x1E3D },
+	{ 0x1E3E, 0x1E3F },
+	{ 0x1E40, 0x1E41 },
+	{ 0x1E42, 0x1E43 },
+	{ 0x1E44, 0x1E45 },
+	{ 0x1E46, 0x1E47 },
+	{ 0x1E48, 0x1E49 },
+	{ 0x1E4A, 0x1E4B },
+	{ 0x1E4C, 0x1E4D },
+	{ 0x1E4E, 0x1E4F },
+	{ 0x1E50, 0x1E51 },
+	{ 0x1E52, 0x1E53 },
+	{ 0x1E54, 0x1E55 },
+	{ 0x1E56, 0x1E57 },
+	{ 0x1E58, 0x1E59 },
+	{ 0x1E5A, 0x1E5B },
+	{ 0x1E5C, 0x1E5D },
+	{ 0x1E5E, 0x1E5F },
+	{ 0x1E60, 0x1E61 },
+	{ 0x1E62, 0x1E63 },
+	{ 0x1E64, 0x1E65 },
+	{ 0x1E66, 0x1E67 },
+	{ 0x1E68, 0x1E69 },
+	{ 0x1E6A, 0x1E6B },
+	{ 0x1E6C, 0x1E6D },
+	{ 0x1E6E, 0x1E6F },
+	{ 0x1E70, 0x1E71 },
+	{ 0x1E72, 0x1E73 },
+	{ 0x1E74, 0x1E75 },
+	{ 0x1E76, 0x1E77 },
+	{ 0x1E78, 0x1E79 },
+	{ 0x1E7A, 0x1E7B },
+	{ 0x1E7C, 0x1E7D },
+	{ 0x1E7E, 0x1E7F },
+	{ 0x1E80, 0x1E81 },
+	{ 0x1E82, 0x1E83 },
+	{ 0x1E84, 0x1E85 },
+	{ 0x1E86, 0x1E87 },
+	{ 0x1E88, 0x1E89 },
+	{ 0x1E8A, 0x1E8B },
+	{ 0x1E8C, 0x1E8D },
+	{ 0x1E8E, 0x1E8F },
+	{ 0x1E90, 0x1E91 },
+	{ 0x1E92, 0x1E93 },
+	{ 0x1E94, 0x1E95 },
+	{ 0x1EA0, 0x1EA1 },
+	{ 0x1EA2, 0x1EA3 },
+	{ 0x1EA4, 0x1EA5 },
+	{ 0x1EA6, 0x1EA7 },
+	{ 0x1EA8, 0x1EA9 },
+	{ 0x1EAA, 0x1EAB },
+	{ 0x1EAC, 0x1EAD },
+	{ 0x1EAE, 0x1EAF },
+	{ 0x1EB0, 0x1EB1 },
+	{ 0x1EB2, 0x1EB3 },
+	{ 0x1EB4, 0x1EB5 },
+	{ 0x1EB6, 0x1EB7 },
+	{ 0x1EB8, 0x1EB9 },
+	{ 0x1EBA, 0x1EBB },
+	{ 0x1EBC, 0x1EBD },
+	{ 0x1EBE, 0x1EBF },
+	{ 0x1EC0, 0x1EC1 },
+	{ 0x1EC2, 0x1EC3 },
+	{ 0x1EC4, 0x1EC5 },
+	{ 0x1EC6, 0x1EC7 },
+	{ 0x1EC8, 0x1EC9 },
+	{ 0x1ECA, 0x1ECB },
+	{ 0x1ECC, 0x1ECD },
+	{ 0x1ECE, 0x1ECF },
+	{ 0x1ED0, 0x1ED1 },
+	{ 0x1ED2, 0x1ED3 },
+	{ 0x1ED4, 0x1ED5 },
+	{ 0x1ED6, 0x1ED7 },
+	{ 0x1ED8, 0x1ED9 },
+	{ 0x1EDA, 0x1EDB },
+	{ 0x1EDC, 0x1EDD },
+	{ 0x1EDE, 0x1EDF },
+	{ 0x1EE0, 0x1EE1 },
+	{ 0x1EE2, 0x1EE3 },
+	{ 0x1EE4, 0x1EE5 },
+	{ 0x1EE6, 0x1EE7 },
+	{ 0x1EE8, 0x1EE9 },
+	{ 0x1EEA, 0x1EEB },
+	{ 0x1EEC, 0x1EED },
+	{ 0x1EEE, 0x1EEF },
+	{ 0x1EF0, 0x1EF1 },
+	{ 0x1EF2, 0x1EF3 },
+	{ 0x1EF4, 0x1EF5 },
+	{ 0x1EF6, 0x1EF7 },
+	{ 0x1EF8, 0x1EF9 },
+	{ 0x1F08, 0x1F00 },
+	{ 0x1F09, 0x1F01 },
+	{ 0x1F0A, 0x1F02 },
+	{ 0x1F0B, 0x1F03 },
+	{ 0x1F0C, 0x1F04 },
+	{ 0x1F0D, 0x1F05 },
+	{ 0x1F0E, 0x1F06 },
+	{ 0x1F0F, 0x1F07 },
+	{ 0x1F18, 0x1F10 },
+	{ 0x1F19, 0x1F11 },
+	{ 0x1F1A, 0x1F12 },
+	{ 0x1F1B, 0x1F13 },
+	{ 0x1F1C, 0x1F14 },
+	{ 0x1F1D, 0x1F15 },
+	{ 0x1F28, 0x1F20 },
+	{ 0x1F29, 0x1F21 },
+	{ 0x1F2A, 0x1F22 },
+	{ 0x1F2B, 0x1F23 },
+	{ 0x1F2C, 0x1F24 },
+	{ 0x1F2D, 0x1F25 },
+	{ 0x1F2E, 0x1F26 },
+	{ 0x1F2F, 0x1F27 },
+	{ 0x1F38, 0x1F30 },
+	{ 0x1F39, 0x1F31 },
+	{ 0x1F3A, 0x1F32 },
+	{ 0x1F3B, 0x1F33 },
+	{ 0x1F3C, 0x1F34 },
+	{ 0x1F3D, 0x1F35 },
+	{ 0x1F3E, 0x1F36 },
+	{ 0x1F3F, 0x1F37 },
+	{ 0x1F48, 0x1F40 },
+	{ 0x1F49, 0x1F41 },
+	{ 0x1F4A, 0x1F42 },
+	{ 0x1F4B, 0x1F43 },
+	{ 0x1F4C, 0x1F44 },
+	{ 0x1F4D, 0x1F45 },
+	{ 0x1F59, 0x1F51 },
+	{ 0x1F5B, 0x1F53 },
+	{ 0x1F5D, 0x1F55 },
+	{ 0x1F5F, 0x1F57 },
+	{ 0x1F68, 0x1F60 },
+	{ 0x1F69, 0x1F61 },
+	{ 0x1F6A, 0x1F62 },
+	{ 0x1F6B, 0x1F63 },
+	{ 0x1F6C, 0x1F64 },
+	{ 0x1F6D, 0x1F65 },
+	{ 0x1F6E, 0x1F66 },
+	{ 0x1F6F, 0x1F67 },
+	{ 0x1F88, 0x1F80 },
+	{ 0x1F89, 0x1F81 },
+	{ 0x1F8A, 0x1F82 },
+	{ 0x1F8B, 0x1F83 },
+	{ 0x1F8C, 0x1F84 },
+	{ 0x1F8D, 0x1F85 },
+	{ 0x1F8E, 0x1F86 },
+	{ 0x1F8F, 0x1F87 },
+	{ 0x1F98, 0x1F90 },
+	{ 0x1F99, 0x1F91 },
+	{ 0x1F9A, 0x1F92 },
+	{ 0x1F9B, 0x1F93 },
+	{ 0x1F9C, 0x1F94 },
+	{ 0x1F9D, 0x1F95 },
+	{ 0x1F9E, 0x1F96 },
+	{ 0x1F9F, 0x1F97 },
+	{ 0x1FA8, 0x1FA0 },
+	{ 0x1FA9, 0x1FA1 },
+	{ 0x1FAA, 0x1FA2 },
+	{ 0x1FAB, 0x1FA3 },
+	{ 0x1FAC, 0x1FA4 },
+	{ 0x1FAD, 0x1FA5 },
+	{ 0x1FAE, 0x1FA6 },
+	{ 0x1FAF, 0x1FA7 },
+	{ 0x1FB8, 0x1FB0 },
+	{ 0x1FB9, 0x1FB1 },
+	{ 0x1FD8, 0x1FD0 },
+	{ 0x1FD9, 0x1FD1 },
+	{ 0x1FE8, 0x1FE0 },
+	{ 0x1FE9, 0x1FE1 },
+	{ 0x24B6, 0x24D0 },
+	{ 0x24B7, 0x24D1 },
+	{ 0x24B8, 0x24D2 },
+	{ 0x24B9, 0x24D3 },
+	{ 0x24BA, 0x24D4 },
+	{ 0x24BB, 0x24D5 },
+	{ 0x24BC, 0x24D6 },
+	{ 0x24BD, 0x24D7 },
+	{ 0x24BE, 0x24D8 },
+	{ 0x24BF, 0x24D9 },
+	{ 0x24C0, 0x24DA },
+	{ 0x24C1, 0x24DB },
+	{ 0x24C2, 0x24DC },
+	{ 0x24C3, 0x24DD },
+	{ 0x24C4, 0x24DE },
+	{ 0x24C5, 0x24DF },
+	{ 0x24C6, 0x24E0 },
+	{ 0x24C7, 0x24E1 },
+	{ 0x24C8, 0x24E2 },
+	{ 0x24C9, 0x24E3 },
+	{ 0x24CA, 0x24E4 },
+	{ 0x24CB, 0x24E5 },
+	{ 0x24CC, 0x24E6 },
+	{ 0x24CD, 0x24E7 },
+	{ 0x24CE, 0x24E8 },
+	{ 0x24CF, 0x24E9 },
+	{ 0xFF21, 0xFF41 },
+	{ 0xFF22, 0xFF42 },
+	{ 0xFF23, 0xFF43 },
+	{ 0xFF24, 0xFF44 },
+	{ 0xFF25, 0xFF45 },
+	{ 0xFF26, 0xFF46 },
+	{ 0xFF27, 0xFF47 },
+	{ 0xFF28, 0xFF48 },
+	{ 0xFF29, 0xFF49 },
+	{ 0xFF2A, 0xFF4A },
+	{ 0xFF2B, 0xFF4B },
+	{ 0xFF2C, 0xFF4C },
+	{ 0xFF2D, 0xFF4D },
+	{ 0xFF2E, 0xFF4E },
+	{ 0xFF2F, 0xFF4F },
+	{ 0xFF30, 0xFF50 },
+	{ 0xFF31, 0xFF51 },
+	{ 0xFF32, 0xFF52 },
+	{ 0xFF33, 0xFF53 },
+	{ 0xFF34, 0xFF54 },
+	{ 0xFF35, 0xFF55 },
+	{ 0xFF36, 0xFF56 },
+	{ 0xFF37, 0xFF57 },
+	{ 0xFF38, 0xFF58 },
+	{ 0xFF39, 0xFF59 },
+	{ 0xFF3A, 0xFF5A },
+};
+
+static int _find_upper(int ch) {
+	int low = 0;
+	int high = CAPS_LEN - 1;
+	int middle;
+
+	while (low <= high) {
+		middle = (low + high) / 2;
+
+		if (ch < caps_table[middle][0]) {
+			high = middle - 1; // search low end of array
+		} else if (caps_table[middle][0] < ch) {
+			low = middle + 1; // search high end of array
+		} else {
+			return caps_table[middle][1];
+		}
+	}
+
+	return ch;
+}
+
+static int _find_lower(int ch) {
+	int low = 0;
+	int high = CAPS_LEN - 2;
+	int middle;
+
+	while (low <= high) {
+		middle = (low + high) / 2;
+
+		if (ch < reverse_caps_table[middle][0]) {
+			high = middle - 1; // search low end of array
+		} else if (reverse_caps_table[middle][0] < ch) {
+			low = middle + 1; // search high end of array
+		} else {
+			return reverse_caps_table[middle][1];
+		}
+	}
+
+	return ch;
+}
+
+#endif // UCAPS_HPP

+ 13 - 0
src/core/memory.cpp

@@ -46,12 +46,24 @@ void Memory::free_static(void *p_ptr) {
 	internal::gdn_interface->mem_free(p_ptr);
 }
 
+_GlobalNil::_GlobalNil() {
+	left = this;
+	right = this;
+	parent = this;
+}
+
+_GlobalNil _GlobalNilClass::_nil;
+
 } // namespace godot
 
 void *operator new(size_t p_size, const char *p_description) {
 	return godot::Memory::alloc_static(p_size);
 }
 
+void *operator new(size_t p_size, void *(*p_allocfunc)(size_t p_size)) {
+	return p_allocfunc(p_size);
+}
+
 using namespace godot;
 
 #ifdef _MSC_VER
@@ -69,4 +81,5 @@ void operator delete(void *p_mem, void *p_pointer, size_t check, const char *p_d
 	ERR_PRINT("Call to placement delete should not happen.");
 	CRASH_NOW();
 }
+
 #endif