Sync containers with new HashMap/HashSet, sync API headers.
parent
851ec2f923
commit
e3119e7d05
File diff suppressed because it is too large
Load Diff
|
@ -114,6 +114,7 @@ typedef enum {
|
||||||
GDNATIVE_VARIANT_OP_NEGATE,
|
GDNATIVE_VARIANT_OP_NEGATE,
|
||||||
GDNATIVE_VARIANT_OP_POSITIVE,
|
GDNATIVE_VARIANT_OP_POSITIVE,
|
||||||
GDNATIVE_VARIANT_OP_MODULE,
|
GDNATIVE_VARIANT_OP_MODULE,
|
||||||
|
GDNATIVE_VARIANT_OP_POWER,
|
||||||
/* bitwise */
|
/* bitwise */
|
||||||
GDNATIVE_VARIANT_OP_SHIFT_LEFT,
|
GDNATIVE_VARIANT_OP_SHIFT_LEFT,
|
||||||
GDNATIVE_VARIANT_OP_SHIFT_RIGHT,
|
GDNATIVE_VARIANT_OP_SHIFT_RIGHT,
|
||||||
|
@ -412,6 +413,8 @@ typedef struct {
|
||||||
GDNativeBool (*variant_iter_init)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeBool *r_valid);
|
GDNativeBool (*variant_iter_init)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeBool *r_valid);
|
||||||
GDNativeBool (*variant_iter_next)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeBool *r_valid);
|
GDNativeBool (*variant_iter_next)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeBool *r_valid);
|
||||||
void (*variant_iter_get)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeVariantPtr r_ret, GDNativeBool *r_valid);
|
void (*variant_iter_get)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeVariantPtr r_ret, GDNativeBool *r_valid);
|
||||||
|
GDNativeInt (*variant_hash)(const GDNativeVariantPtr p_self);
|
||||||
|
GDNativeInt (*variant_recursive_hash)(const GDNativeVariantPtr p_self, GDNativeInt p_recursion_count);
|
||||||
GDNativeBool (*variant_hash_compare)(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_other);
|
GDNativeBool (*variant_hash_compare)(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_other);
|
||||||
GDNativeBool (*variant_booleanize)(const GDNativeVariantPtr p_self);
|
GDNativeBool (*variant_booleanize)(const GDNativeVariantPtr p_self);
|
||||||
void (*variant_sub)(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, GDNativeVariantPtr r_dst);
|
void (*variant_sub)(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, GDNativeVariantPtr r_dst);
|
||||||
|
|
|
@ -98,6 +98,14 @@ public:
|
||||||
_ALWAYS_INLINE_ static void free(void *p_ptr) { Memory::free_static(p_ptr); }
|
_ALWAYS_INLINE_ static void free(void *p_ptr) { Memory::free_static(p_ptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class DefaultTypedAllocator {
|
||||||
|
public:
|
||||||
|
template <class... Args>
|
||||||
|
_ALWAYS_INLINE_ T *new_allocation(const Args &&...p_args) { return memnew(T(p_args...)); }
|
||||||
|
_ALWAYS_INLINE_ void delete_allocation(T *p_allocation) { memdelete(p_allocation); }
|
||||||
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void memdelete(T *p_class, typename std::enable_if<!std::is_base_of_v<godot::Wrapped, T>>::type * = 0) {
|
void memdelete(T *p_class, typename std::enable_if<!std::is_base_of_v<godot::Wrapped, T>>::type * = 0) {
|
||||||
if (!__has_trivial_destructor(T)) {
|
if (!__has_trivial_destructor(T)) {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,477 @@
|
||||||
|
/*************************************************************************/
|
||||||
|
/* hash_set.hpp */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2022 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_SET_HPP
|
||||||
|
#define HASH_SET_HPP
|
||||||
|
|
||||||
|
#include <godot_cpp/core/error_macros.hpp>
|
||||||
|
#include <godot_cpp/core/memory.hpp>
|
||||||
|
#include <godot_cpp/templates/hash_map.hpp>
|
||||||
|
#include <godot_cpp/templates/hashfuncs.hpp>
|
||||||
|
#include <godot_cpp/templates/pair.hpp>
|
||||||
|
|
||||||
|
namespace godot {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of Set using a bidi indexed hash map.
|
||||||
|
* Use RBSet instead of this only if the following conditions are met:
|
||||||
|
*
|
||||||
|
* - You need to keep an iterator or const pointer to Key and you intend to add/remove elements in the meantime.
|
||||||
|
* - Iteration order does matter (via operator<)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
template <class TKey,
|
||||||
|
class Hasher = HashMapHasherDefault,
|
||||||
|
class Comparator = HashMapComparatorDefault<TKey>>
|
||||||
|
class HashSet {
|
||||||
|
public:
|
||||||
|
static constexpr uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime.
|
||||||
|
static constexpr float MAX_OCCUPANCY = 0.75;
|
||||||
|
static constexpr uint32_t EMPTY_HASH = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
TKey *keys = nullptr;
|
||||||
|
uint32_t *hash_to_key = nullptr;
|
||||||
|
uint32_t *key_to_hash = nullptr;
|
||||||
|
uint32_t *hashes = nullptr;
|
||||||
|
|
||||||
|
uint32_t capacity_index = 0;
|
||||||
|
uint32_t num_elements = 0;
|
||||||
|
|
||||||
|
_FORCE_INLINE_ uint32_t _hash(const TKey &p_key) const {
|
||||||
|
uint32_t hash = Hasher::hash(p_key);
|
||||||
|
|
||||||
|
if (unlikely(hash == EMPTY_HASH)) {
|
||||||
|
hash = EMPTY_HASH + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ uint32_t _get_probe_length(uint32_t p_pos, uint32_t p_hash, uint32_t p_capacity) const {
|
||||||
|
uint32_t original_pos = p_hash % p_capacity;
|
||||||
|
return (p_pos - original_pos + p_capacity) % p_capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _lookup_pos(const TKey &p_key, uint32_t &r_pos) const {
|
||||||
|
if (keys == nullptr) {
|
||||||
|
return false; // Failed lookups, no elements
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||||
|
uint32_t hash = _hash(p_key);
|
||||||
|
uint32_t pos = hash % capacity;
|
||||||
|
uint32_t distance = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (hashes[pos] == EMPTY_HASH) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (distance > _get_probe_length(pos, hashes[pos], capacity)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hashes[pos] == hash && Comparator::compare(keys[hash_to_key[pos]], p_key)) {
|
||||||
|
r_pos = hash_to_key[pos];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = (pos + 1) % capacity;
|
||||||
|
distance++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t _insert_with_hash(uint32_t p_hash, uint32_t p_index) {
|
||||||
|
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||||
|
uint32_t hash = p_hash;
|
||||||
|
uint32_t index = p_index;
|
||||||
|
uint32_t distance = 0;
|
||||||
|
uint32_t pos = hash % capacity;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (hashes[pos] == EMPTY_HASH) {
|
||||||
|
hashes[pos] = hash;
|
||||||
|
key_to_hash[index] = pos;
|
||||||
|
hash_to_key[pos] = index;
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not an empty slot, let's check the probing length of the existing one.
|
||||||
|
uint32_t existing_probe_len = _get_probe_length(pos, hashes[pos], capacity);
|
||||||
|
if (existing_probe_len < distance) {
|
||||||
|
key_to_hash[index] = pos;
|
||||||
|
SWAP(hash, hashes[pos]);
|
||||||
|
SWAP(index, hash_to_key[pos]);
|
||||||
|
distance = existing_probe_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = (pos + 1) % capacity;
|
||||||
|
distance++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _resize_and_rehash(uint32_t p_new_capacity_index) {
|
||||||
|
// Capacity can't be 0.
|
||||||
|
capacity_index = MAX((uint32_t)MIN_CAPACITY_INDEX, p_new_capacity_index);
|
||||||
|
|
||||||
|
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||||
|
|
||||||
|
uint32_t *old_hashes = hashes;
|
||||||
|
uint32_t *old_key_to_hash = key_to_hash;
|
||||||
|
|
||||||
|
hashes = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||||
|
keys = reinterpret_cast<TKey *>(Memory::realloc_static(keys, sizeof(TKey) * capacity));
|
||||||
|
key_to_hash = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||||
|
hash_to_key = reinterpret_cast<uint32_t *>(Memory::realloc_static(hash_to_key, sizeof(uint32_t) * capacity));
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < capacity; i++) {
|
||||||
|
hashes[i] = EMPTY_HASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < num_elements; i++) {
|
||||||
|
uint32_t h = old_hashes[old_key_to_hash[i]];
|
||||||
|
_insert_with_hash(h, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
Memory::free_static(old_hashes);
|
||||||
|
Memory::free_static(old_key_to_hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ int32_t _insert(const TKey &p_key) {
|
||||||
|
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||||
|
if (unlikely(keys == nullptr)) {
|
||||||
|
// Allocate on demand to save memory.
|
||||||
|
|
||||||
|
hashes = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||||
|
keys = reinterpret_cast<TKey *>(Memory::alloc_static(sizeof(TKey) * capacity));
|
||||||
|
key_to_hash = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||||
|
hash_to_key = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < capacity; i++) {
|
||||||
|
hashes[i] = EMPTY_HASH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t pos = 0;
|
||||||
|
bool exists = _lookup_pos(p_key, pos);
|
||||||
|
|
||||||
|
if (exists) {
|
||||||
|
return pos;
|
||||||
|
} else {
|
||||||
|
if (num_elements + 1 > MAX_OCCUPANCY * capacity) {
|
||||||
|
ERR_FAIL_COND_V_MSG(capacity_index + 1 == HASH_TABLE_SIZE_MAX, -1, "Hash table maximum capacity reached, aborting insertion.");
|
||||||
|
_resize_and_rehash(capacity_index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t hash = _hash(p_key);
|
||||||
|
memnew_placement(&keys[num_elements], TKey(p_key));
|
||||||
|
_insert_with_hash(hash, num_elements);
|
||||||
|
num_elements++;
|
||||||
|
return num_elements - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _init_from(const HashSet &p_other) {
|
||||||
|
capacity_index = p_other.capacity_index;
|
||||||
|
num_elements = p_other.num_elements;
|
||||||
|
|
||||||
|
if (p_other.num_elements == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||||
|
|
||||||
|
hashes = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||||
|
keys = reinterpret_cast<TKey *>(Memory::alloc_static(sizeof(TKey) * capacity));
|
||||||
|
key_to_hash = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||||
|
hash_to_key = reinterpret_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity));
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < num_elements; i++) {
|
||||||
|
memnew_placement(&keys[i], TKey(p_other.keys[i]));
|
||||||
|
key_to_hash[i] = p_other.key_to_hash[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < capacity; i++) {
|
||||||
|
hashes[i] = p_other.hashes[i];
|
||||||
|
hash_to_key[i] = p_other.hash_to_key[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
_FORCE_INLINE_ uint32_t get_capacity() const { return hash_table_size_primes[capacity_index]; }
|
||||||
|
_FORCE_INLINE_ uint32_t size() const { return num_elements; }
|
||||||
|
|
||||||
|
/* Standard Godot Container API */
|
||||||
|
|
||||||
|
bool is_empty() const {
|
||||||
|
return num_elements == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
if (keys == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||||
|
for (uint32_t i = 0; i < capacity; i++) {
|
||||||
|
hashes[i] = EMPTY_HASH;
|
||||||
|
}
|
||||||
|
for (uint32_t i = 0; i < num_elements; i++) {
|
||||||
|
keys[i].~TKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
num_elements = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ bool has(const TKey &p_key) const {
|
||||||
|
uint32_t _pos = 0;
|
||||||
|
return _lookup_pos(p_key, _pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool erase(const TKey &p_key) {
|
||||||
|
uint32_t pos = 0;
|
||||||
|
bool exists = _lookup_pos(p_key, pos);
|
||||||
|
|
||||||
|
if (!exists) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t key_pos = pos;
|
||||||
|
pos = key_to_hash[pos]; // make hash pos
|
||||||
|
|
||||||
|
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||||
|
uint32_t next_pos = (pos + 1) % capacity;
|
||||||
|
while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity) != 0) {
|
||||||
|
uint32_t kpos = hash_to_key[pos];
|
||||||
|
uint32_t kpos_next = hash_to_key[next_pos];
|
||||||
|
SWAP(key_to_hash[kpos], key_to_hash[kpos_next]);
|
||||||
|
SWAP(hashes[next_pos], hashes[pos]);
|
||||||
|
SWAP(hash_to_key[next_pos], hash_to_key[pos]);
|
||||||
|
|
||||||
|
pos = next_pos;
|
||||||
|
next_pos = (pos + 1) % capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
hashes[pos] = EMPTY_HASH;
|
||||||
|
keys[key_pos].~TKey();
|
||||||
|
num_elements--;
|
||||||
|
if (key_pos < num_elements) {
|
||||||
|
// Not the last key, move the last one here to keep keys lineal
|
||||||
|
memnew_placement(&keys[key_pos], TKey(keys[num_elements]));
|
||||||
|
keys[num_elements].~TKey();
|
||||||
|
key_to_hash[key_pos] = key_to_hash[num_elements];
|
||||||
|
hash_to_key[key_to_hash[num_elements]] = key_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reserves space for a number of elements, useful to avoid many resizes and rehashes.
|
||||||
|
// If adding a known (possibly large) number of elements at once, must be larger than old capacity.
|
||||||
|
void reserve(uint32_t p_new_capacity) {
|
||||||
|
uint32_t new_index = capacity_index;
|
||||||
|
|
||||||
|
while (hash_table_size_primes[new_index] < p_new_capacity) {
|
||||||
|
ERR_FAIL_COND_MSG(new_index + 1 == (uint32_t)HASH_TABLE_SIZE_MAX, nullptr);
|
||||||
|
new_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_index == capacity_index) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keys == nullptr) {
|
||||||
|
capacity_index = new_index;
|
||||||
|
return; // Unallocated yet.
|
||||||
|
}
|
||||||
|
_resize_and_rehash(new_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Iterator API **/
|
||||||
|
|
||||||
|
struct Iterator {
|
||||||
|
_FORCE_INLINE_ const TKey &operator*() const {
|
||||||
|
return keys[index];
|
||||||
|
}
|
||||||
|
_FORCE_INLINE_ const TKey *operator->() const {
|
||||||
|
return &keys[index];
|
||||||
|
}
|
||||||
|
_FORCE_INLINE_ Iterator &operator++() {
|
||||||
|
index++;
|
||||||
|
if (index >= (int32_t)num_keys) {
|
||||||
|
index = -1;
|
||||||
|
keys = nullptr;
|
||||||
|
num_keys = 0;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
_FORCE_INLINE_ Iterator &operator--() {
|
||||||
|
index--;
|
||||||
|
if (index < 0) {
|
||||||
|
index = -1;
|
||||||
|
keys = nullptr;
|
||||||
|
num_keys = 0;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return keys == b.keys && index == b.index; }
|
||||||
|
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return keys != b.keys || index != b.index; }
|
||||||
|
|
||||||
|
_FORCE_INLINE_ explicit operator bool() const {
|
||||||
|
return keys != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ Iterator(const TKey *p_keys, uint32_t p_num_keys, int32_t p_index = -1) {
|
||||||
|
keys = p_keys;
|
||||||
|
num_keys = p_num_keys;
|
||||||
|
index = p_index;
|
||||||
|
}
|
||||||
|
_FORCE_INLINE_ Iterator() {}
|
||||||
|
_FORCE_INLINE_ Iterator(const Iterator &p_it) {
|
||||||
|
keys = p_it.keys;
|
||||||
|
num_keys = p_it.num_keys;
|
||||||
|
index = p_it.index;
|
||||||
|
}
|
||||||
|
_FORCE_INLINE_ void operator=(const Iterator &p_it) {
|
||||||
|
keys = p_it.keys;
|
||||||
|
num_keys = p_it.num_keys;
|
||||||
|
index = p_it.index;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const TKey *keys = nullptr;
|
||||||
|
uint32_t num_keys = 0;
|
||||||
|
int32_t index = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
_FORCE_INLINE_ Iterator begin() const {
|
||||||
|
return num_elements ? Iterator(keys, num_elements, 0) : Iterator();
|
||||||
|
}
|
||||||
|
_FORCE_INLINE_ Iterator end() const {
|
||||||
|
return Iterator();
|
||||||
|
}
|
||||||
|
_FORCE_INLINE_ Iterator last() const {
|
||||||
|
if (num_elements == 0) {
|
||||||
|
return Iterator();
|
||||||
|
}
|
||||||
|
return Iterator(keys, num_elements, num_elements - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ Iterator find(const TKey &p_key) const {
|
||||||
|
uint32_t pos = 0;
|
||||||
|
bool exists = _lookup_pos(p_key, pos);
|
||||||
|
if (!exists) {
|
||||||
|
return end();
|
||||||
|
}
|
||||||
|
return Iterator(keys, num_elements, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ void remove(const Iterator &p_iter) {
|
||||||
|
if (p_iter) {
|
||||||
|
erase(*p_iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert */
|
||||||
|
|
||||||
|
Iterator insert(const TKey &p_key) {
|
||||||
|
uint32_t pos = _insert(p_key);
|
||||||
|
return Iterator(keys, num_elements, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Constructors */
|
||||||
|
|
||||||
|
HashSet(const HashSet &p_other) {
|
||||||
|
_init_from(p_other);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator=(const HashSet &p_other) {
|
||||||
|
if (this == &p_other) {
|
||||||
|
return; // Ignore self assignment.
|
||||||
|
}
|
||||||
|
|
||||||
|
clear();
|
||||||
|
|
||||||
|
if (keys != nullptr) {
|
||||||
|
Memory::free_static(keys);
|
||||||
|
Memory::free_static(key_to_hash);
|
||||||
|
Memory::free_static(hash_to_key);
|
||||||
|
Memory::free_static(hashes);
|
||||||
|
keys = nullptr;
|
||||||
|
hashes = nullptr;
|
||||||
|
hash_to_key = nullptr;
|
||||||
|
key_to_hash = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
_init_from(p_other);
|
||||||
|
}
|
||||||
|
|
||||||
|
HashSet(uint32_t p_initial_capacity) {
|
||||||
|
// Capacity can't be 0.
|
||||||
|
capacity_index = 0;
|
||||||
|
reserve(p_initial_capacity);
|
||||||
|
}
|
||||||
|
HashSet() {
|
||||||
|
capacity_index = MIN_CAPACITY_INDEX;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
clear();
|
||||||
|
|
||||||
|
if (keys != nullptr) {
|
||||||
|
Memory::free_static(keys);
|
||||||
|
Memory::free_static(key_to_hash);
|
||||||
|
Memory::free_static(hash_to_key);
|
||||||
|
Memory::free_static(hashes);
|
||||||
|
keys = nullptr;
|
||||||
|
hashes = nullptr;
|
||||||
|
hash_to_key = nullptr;
|
||||||
|
key_to_hash = nullptr;
|
||||||
|
}
|
||||||
|
capacity_index = MIN_CAPACITY_INDEX;
|
||||||
|
}
|
||||||
|
|
||||||
|
~HashSet() {
|
||||||
|
clear();
|
||||||
|
|
||||||
|
if (keys != nullptr) {
|
||||||
|
Memory::free_static(keys);
|
||||||
|
Memory::free_static(key_to_hash);
|
||||||
|
Memory::free_static(hash_to_key);
|
||||||
|
Memory::free_static(hashes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace godot
|
||||||
|
|
||||||
|
#endif // HASH_SET_HPP
|
|
@ -32,7 +32,19 @@
|
||||||
#define HASHFUNCS_HPP
|
#define HASHFUNCS_HPP
|
||||||
|
|
||||||
#include <godot_cpp/core/math.hpp>
|
#include <godot_cpp/core/math.hpp>
|
||||||
|
#include <godot_cpp/core/object.hpp>
|
||||||
|
#include <godot_cpp/variant/aabb.hpp>
|
||||||
|
#include <godot_cpp/variant/node_path.hpp>
|
||||||
|
#include <godot_cpp/variant/rect2.hpp>
|
||||||
|
#include <godot_cpp/variant/rect2i.hpp>
|
||||||
#include <godot_cpp/variant/rid.hpp>
|
#include <godot_cpp/variant/rid.hpp>
|
||||||
|
#include <godot_cpp/variant/string.hpp>
|
||||||
|
#include <godot_cpp/variant/string_name.hpp>
|
||||||
|
#include <godot_cpp/variant/variant.hpp>
|
||||||
|
#include <godot_cpp/variant/vector2.hpp>
|
||||||
|
#include <godot_cpp/variant/vector2i.hpp>
|
||||||
|
#include <godot_cpp/variant/vector3.hpp>
|
||||||
|
#include <godot_cpp/variant/vector3i.hpp>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hashing functions
|
* Hashing functions
|
||||||
|
@ -152,9 +164,14 @@ static inline uint64_t make_uint64_t(T p_in) {
|
||||||
return _u._u64;
|
return _u._u64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class Ref;
|
||||||
|
|
||||||
struct HashMapHasherDefault {
|
struct HashMapHasherDefault {
|
||||||
|
static _FORCE_INLINE_ uint32_t hash(const String &p_string) { return p_string.hash(); }
|
||||||
static _FORCE_INLINE_ uint32_t hash(const char *p_cstr) { return hash_djb2(p_cstr); }
|
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 uint64_t p_int) { return hash_one_uint64(p_int); }
|
||||||
|
static _FORCE_INLINE_ uint32_t hash(const ObjectID &p_id) { return hash_one_uint64(p_id); }
|
||||||
|
|
||||||
static _FORCE_INLINE_ uint32_t hash(const int64_t p_int) { return hash(uint64_t(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 float p_float) { return hash_djb2_one_float(p_float); }
|
||||||
|
@ -169,6 +186,60 @@ struct HashMapHasherDefault {
|
||||||
static _FORCE_INLINE_ uint32_t hash(const char16_t p_uchar) { return (uint32_t)p_uchar; }
|
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 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()); }
|
static _FORCE_INLINE_ uint32_t hash(const RID &p_rid) { return hash_one_uint64(p_rid.get_id()); }
|
||||||
|
|
||||||
|
static _FORCE_INLINE_ uint32_t hash(const StringName &p_string_name) { return p_string_name.hash(); }
|
||||||
|
static _FORCE_INLINE_ uint32_t hash(const NodePath &p_path) { return p_path.hash(); }
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
static _FORCE_INLINE_ uint32_t hash(const T *p_pointer) { return hash_one_uint64((uint64_t)p_pointer); }
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
static _FORCE_INLINE_ uint32_t hash(const Ref<T> &p_ref) { return hash_one_uint64((uint64_t)p_ref.operator->()); }
|
||||||
|
|
||||||
|
static _FORCE_INLINE_ uint32_t hash(const Vector2i &p_vec) {
|
||||||
|
uint32_t h = hash_djb2_one_32(p_vec.x);
|
||||||
|
return hash_djb2_one_32(p_vec.y, h);
|
||||||
|
}
|
||||||
|
static _FORCE_INLINE_ uint32_t hash(const Vector3i &p_vec) {
|
||||||
|
uint32_t h = hash_djb2_one_32(p_vec.x);
|
||||||
|
h = hash_djb2_one_32(p_vec.y, h);
|
||||||
|
return hash_djb2_one_32(p_vec.z, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
static _FORCE_INLINE_ uint32_t hash(const Vector2 &p_vec) {
|
||||||
|
uint32_t h = hash_djb2_one_float(p_vec.x);
|
||||||
|
return hash_djb2_one_float(p_vec.y, h);
|
||||||
|
}
|
||||||
|
static _FORCE_INLINE_ uint32_t hash(const Vector3 &p_vec) {
|
||||||
|
uint32_t h = hash_djb2_one_float(p_vec.x);
|
||||||
|
h = hash_djb2_one_float(p_vec.y, h);
|
||||||
|
return hash_djb2_one_float(p_vec.z, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
static _FORCE_INLINE_ uint32_t hash(const Rect2i &p_rect) {
|
||||||
|
uint32_t h = hash_djb2_one_32(p_rect.position.x);
|
||||||
|
h = hash_djb2_one_32(p_rect.position.y, h);
|
||||||
|
h = hash_djb2_one_32(p_rect.size.x, h);
|
||||||
|
return hash_djb2_one_32(p_rect.size.y, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
static _FORCE_INLINE_ uint32_t hash(const Rect2 &p_rect) {
|
||||||
|
uint32_t h = hash_djb2_one_float(p_rect.position.x);
|
||||||
|
h = hash_djb2_one_float(p_rect.position.y, h);
|
||||||
|
h = hash_djb2_one_float(p_rect.size.x, h);
|
||||||
|
return hash_djb2_one_float(p_rect.size.y, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
static _FORCE_INLINE_ uint32_t hash(const AABB &p_aabb) {
|
||||||
|
uint32_t h = hash_djb2_one_float(p_aabb.position.x);
|
||||||
|
h = hash_djb2_one_float(p_aabb.position.y, h);
|
||||||
|
h = hash_djb2_one_float(p_aabb.position.z, h);
|
||||||
|
h = hash_djb2_one_float(p_aabb.size.x, h);
|
||||||
|
h = hash_djb2_one_float(p_aabb.size.y, h);
|
||||||
|
return hash_djb2_one_float(p_aabb.size.z, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
// static _FORCE_INLINE_ uint32_t hash(const void* p_ptr) { return uint32_t(uint64_t(p_ptr))*(0x9e3779b1L); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -176,16 +247,70 @@ struct HashMapComparatorDefault {
|
||||||
static bool compare(const T &p_lhs, const T &p_rhs) {
|
static bool compare(const T &p_lhs, const T &p_rhs) {
|
||||||
return p_lhs == p_rhs;
|
return p_lhs == p_rhs;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
bool compare(const float &p_lhs, const float &p_rhs) {
|
template <>
|
||||||
return (p_lhs == p_rhs) || (std::isnan(p_lhs) && std::isnan(p_rhs));
|
struct HashMapComparatorDefault<float> {
|
||||||
}
|
static bool compare(const float &p_lhs, const float &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));
|
return (p_lhs == p_rhs) || (std::isnan(p_lhs) && std::isnan(p_rhs));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct HashMapComparatorDefault<double> {
|
||||||
|
static bool compare(const double &p_lhs, const double &p_rhs) {
|
||||||
|
return (p_lhs == p_rhs) || (std::isnan(p_lhs) && std::isnan(p_rhs));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct HashMapComparatorDefault<Vector2> {
|
||||||
|
static bool compare(const Vector2 &p_lhs, const Vector2 &p_rhs) {
|
||||||
|
return ((p_lhs.x == p_rhs.x) || (std::isnan(p_lhs.x) && std::isnan(p_rhs.x))) && ((p_lhs.y == p_rhs.y) || (std::isnan(p_lhs.y) && std::isnan(p_rhs.y)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct HashMapComparatorDefault<Vector3> {
|
||||||
|
static bool compare(const Vector3 &p_lhs, const Vector3 &p_rhs) {
|
||||||
|
return ((p_lhs.x == p_rhs.x) || (std::isnan(p_lhs.x) && std::isnan(p_rhs.x))) && ((p_lhs.y == p_rhs.y) || (std::isnan(p_lhs.y) && std::isnan(p_rhs.y))) && ((p_lhs.z == p_rhs.z) || (std::isnan(p_lhs.z) && std::isnan(p_rhs.z)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr uint32_t HASH_TABLE_SIZE_MAX = 29;
|
||||||
|
|
||||||
|
const uint32_t hash_table_size_primes[HASH_TABLE_SIZE_MAX] = {
|
||||||
|
5,
|
||||||
|
13,
|
||||||
|
23,
|
||||||
|
47,
|
||||||
|
97,
|
||||||
|
193,
|
||||||
|
389,
|
||||||
|
769,
|
||||||
|
1543,
|
||||||
|
3079,
|
||||||
|
6151,
|
||||||
|
12289,
|
||||||
|
24593,
|
||||||
|
49157,
|
||||||
|
98317,
|
||||||
|
196613,
|
||||||
|
393241,
|
||||||
|
786433,
|
||||||
|
1572869,
|
||||||
|
3145739,
|
||||||
|
6291469,
|
||||||
|
12582917,
|
||||||
|
25165843,
|
||||||
|
50331653,
|
||||||
|
100663319,
|
||||||
|
201326611,
|
||||||
|
402653189,
|
||||||
|
805306457,
|
||||||
|
1610612741,
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace godot
|
} // namespace godot
|
||||||
|
|
||||||
#endif // ! HASHFUNCS_HPP
|
#endif // HASHFUNCS_HPP
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
/* map.hpp */
|
/* rb_map.hpp */
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
/* This file is part of: */
|
/* This file is part of: */
|
||||||
/* GODOT ENGINE */
|
/* GODOT ENGINE */
|
||||||
|
@ -28,8 +28,8 @@
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
|
|
||||||
#ifndef MAP_HPP
|
#ifndef RB_MAP_HPP
|
||||||
#define MAP_HPP
|
#define RB_MAP_HPP
|
||||||
|
|
||||||
#include <godot_cpp/core/error_macros.hpp>
|
#include <godot_cpp/core/error_macros.hpp>
|
||||||
#include <godot_cpp/core/memory.hpp>
|
#include <godot_cpp/core/memory.hpp>
|
||||||
|
@ -41,7 +41,7 @@ namespace godot {
|
||||||
// https://web.archive.org/web/20120507164830/https://web.mit.edu/~emin/www/source_code/red_black_tree/index.html
|
// 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>
|
template <class K, class V, class C = Comparator<K>, class A = DefaultAllocator>
|
||||||
class Map {
|
class RBMap {
|
||||||
enum Color {
|
enum Color {
|
||||||
RED,
|
RED,
|
||||||
BLACK
|
BLACK
|
||||||
|
@ -51,7 +51,7 @@ class Map {
|
||||||
public:
|
public:
|
||||||
class Element {
|
class Element {
|
||||||
private:
|
private:
|
||||||
friend class Map<K, V, C, A>;
|
friend class RBMap<K, V, C, A>;
|
||||||
int color = RED;
|
int color = RED;
|
||||||
Element *right = nullptr;
|
Element *right = nullptr;
|
||||||
Element *left = nullptr;
|
Element *left = nullptr;
|
||||||
|
@ -113,7 +113,9 @@ public:
|
||||||
|
|
||||||
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
|
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
|
||||||
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
|
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
|
||||||
|
explicit operator bool() const {
|
||||||
|
return E != nullptr;
|
||||||
|
}
|
||||||
Iterator(Element *p_E) { E = p_E; }
|
Iterator(Element *p_E) { E = p_E; }
|
||||||
Iterator() {}
|
Iterator() {}
|
||||||
Iterator(const Iterator &p_it) { E = p_it.E; }
|
Iterator(const Iterator &p_it) { E = p_it.E; }
|
||||||
|
@ -138,7 +140,9 @@ public:
|
||||||
|
|
||||||
_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_ bool operator!=(const ConstIterator &b) const { return E != b.E; }
|
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return E != b.E; }
|
||||||
|
explicit operator bool() const {
|
||||||
|
return E != nullptr;
|
||||||
|
}
|
||||||
ConstIterator(const Element *p_E) { E = p_E; }
|
ConstIterator(const Element *p_E) { E = p_E; }
|
||||||
ConstIterator() {}
|
ConstIterator() {}
|
||||||
ConstIterator(const ConstIterator &p_it) { E = p_it.E; }
|
ConstIterator(const ConstIterator &p_it) { E = p_it.E; }
|
||||||
|
@ -180,7 +184,7 @@ public:
|
||||||
private:
|
private:
|
||||||
struct _Data {
|
struct _Data {
|
||||||
Element *_root = nullptr;
|
Element *_root = nullptr;
|
||||||
Element *_nil;
|
Element *_nil = nullptr;
|
||||||
int size_cache = 0;
|
int size_cache = 0;
|
||||||
|
|
||||||
_FORCE_INLINE_ _Data() {
|
_FORCE_INLINE_ _Data() {
|
||||||
|
@ -346,7 +350,7 @@ private:
|
||||||
void _insert_rb_fix(Element *p_new_node) {
|
void _insert_rb_fix(Element *p_new_node) {
|
||||||
Element *node = p_new_node;
|
Element *node = p_new_node;
|
||||||
Element *nparent = node->parent;
|
Element *nparent = node->parent;
|
||||||
Element *ngrand_parent;
|
Element *ngrand_parent = nullptr;
|
||||||
|
|
||||||
while (nparent->color == RED) {
|
while (nparent->color == RED) {
|
||||||
ngrand_parent = nparent->parent;
|
ngrand_parent = nparent->parent;
|
||||||
|
@ -502,7 +506,7 @@ private:
|
||||||
Element *rp = ((p_node->left == _data._nil) || (p_node->right == _data._nil)) ? p_node : p_node->_next;
|
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 *node = (rp->left == _data._nil) ? rp->right : rp->left;
|
||||||
|
|
||||||
Element *sibling;
|
Element *sibling = nullptr;
|
||||||
if (rp == rp->parent->left) {
|
if (rp == rp->parent->left) {
|
||||||
rp->parent->left = node;
|
rp->parent->left = node;
|
||||||
sibling = rp->parent->right;
|
sibling = rp->parent->right;
|
||||||
|
@ -574,7 +578,7 @@ private:
|
||||||
memdelete_allocator<Element, A>(p_element);
|
memdelete_allocator<Element, A>(p_element);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _copy_from(const Map &p_map) {
|
void _copy_from(const RBMap &p_map) {
|
||||||
clear();
|
clear();
|
||||||
// not the fastest way, but safeset to write.
|
// not the fastest way, but safeset to write.
|
||||||
for (Element *I = p_map.front(); I; I = I->next()) {
|
for (Element *I = p_map.front(); I; I = I->next()) {
|
||||||
|
@ -712,8 +716,12 @@ public:
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool is_empty() const { return _data.size_cache == 0; }
|
inline bool is_empty() const {
|
||||||
inline int size() const { return _data.size_cache; }
|
return _data.size_cache == 0;
|
||||||
|
}
|
||||||
|
inline int size() const {
|
||||||
|
return _data.size_cache;
|
||||||
|
}
|
||||||
|
|
||||||
int calculate_depth() const {
|
int calculate_depth() const {
|
||||||
// used for debug mostly
|
// used for debug mostly
|
||||||
|
@ -737,21 +745,21 @@ public:
|
||||||
_data._free_root();
|
_data._free_root();
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator=(const Map &p_map) {
|
void operator=(const RBMap &p_map) {
|
||||||
_copy_from(p_map);
|
_copy_from(p_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map(const Map &p_map) {
|
RBMap(const RBMap &p_map) {
|
||||||
_copy_from(p_map);
|
_copy_from(p_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
_FORCE_INLINE_ Map() {}
|
_FORCE_INLINE_ RBMap() {}
|
||||||
|
|
||||||
~Map() {
|
~RBMap() {
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace godot
|
} // namespace godot
|
||||||
|
|
||||||
#endif // ! MAP_HPP
|
#endif // MAP_HPP
|
|
@ -1,5 +1,5 @@
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
/* set.hpp */
|
/* rb_set.hpp */
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
/* This file is part of: */
|
/* This file is part of: */
|
||||||
/* GODOT ENGINE */
|
/* GODOT ENGINE */
|
||||||
|
@ -28,8 +28,8 @@
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
|
|
||||||
#ifndef SET_HPP
|
#ifndef RB_SET_HPP
|
||||||
#define SET_HPP
|
#define RB_SET_HPP
|
||||||
|
|
||||||
#include <godot_cpp/core/memory.hpp>
|
#include <godot_cpp/core/memory.hpp>
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@
|
||||||
namespace godot {
|
namespace godot {
|
||||||
|
|
||||||
template <class T, class C = Comparator<T>, class A = DefaultAllocator>
|
template <class T, class C = Comparator<T>, class A = DefaultAllocator>
|
||||||
class Set {
|
class RBSet {
|
||||||
enum Color {
|
enum Color {
|
||||||
RED,
|
RED,
|
||||||
BLACK
|
BLACK
|
||||||
|
@ -49,7 +49,7 @@ class Set {
|
||||||
public:
|
public:
|
||||||
class Element {
|
class Element {
|
||||||
private:
|
private:
|
||||||
friend class Set<T, C, A>;
|
friend class RBSet<T, C, A>;
|
||||||
int color = RED;
|
int color = RED;
|
||||||
Element *right = nullptr;
|
Element *right = nullptr;
|
||||||
Element *left = nullptr;
|
Element *left = nullptr;
|
||||||
|
@ -100,6 +100,7 @@ public:
|
||||||
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
|
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
|
||||||
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
|
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
|
||||||
|
|
||||||
|
explicit operator bool() const { return E != nullptr; }
|
||||||
Iterator(Element *p_E) { E = p_E; }
|
Iterator(Element *p_E) { E = p_E; }
|
||||||
Iterator() {}
|
Iterator() {}
|
||||||
Iterator(const Iterator &p_it) { E = p_it.E; }
|
Iterator(const Iterator &p_it) { E = p_it.E; }
|
||||||
|
@ -129,6 +130,8 @@ public:
|
||||||
_FORCE_INLINE_ ConstIterator() {}
|
_FORCE_INLINE_ ConstIterator() {}
|
||||||
_FORCE_INLINE_ ConstIterator(const ConstIterator &p_it) { E = p_it.E; }
|
_FORCE_INLINE_ ConstIterator(const ConstIterator &p_it) { E = p_it.E; }
|
||||||
|
|
||||||
|
explicit operator bool() const { return E != nullptr; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const Element *E = nullptr;
|
const Element *E = nullptr;
|
||||||
};
|
};
|
||||||
|
@ -329,7 +332,7 @@ private:
|
||||||
void _insert_rb_fix(Element *p_new_node) {
|
void _insert_rb_fix(Element *p_new_node) {
|
||||||
Element *node = p_new_node;
|
Element *node = p_new_node;
|
||||||
Element *nparent = node->parent;
|
Element *nparent = node->parent;
|
||||||
Element *ngrand_parent;
|
Element *ngrand_parent = nullptr;
|
||||||
|
|
||||||
while (nparent->color == RED) {
|
while (nparent->color == RED) {
|
||||||
ngrand_parent = nparent->parent;
|
ngrand_parent = nparent->parent;
|
||||||
|
@ -483,7 +486,7 @@ private:
|
||||||
Element *rp = ((p_node->left == _data._nil) || (p_node->right == _data._nil)) ? p_node : p_node->_next;
|
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 *node = (rp->left == _data._nil) ? rp->right : rp->left;
|
||||||
|
|
||||||
Element *sibling;
|
Element *sibling = nullptr;
|
||||||
if (rp == rp->parent->left) {
|
if (rp == rp->parent->left) {
|
||||||
rp->parent->left = node;
|
rp->parent->left = node;
|
||||||
sibling = rp->parent->right;
|
sibling = rp->parent->right;
|
||||||
|
@ -555,7 +558,7 @@ private:
|
||||||
memdelete_allocator<Element, A>(p_element);
|
memdelete_allocator<Element, A>(p_element);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _copy_from(const Set &p_set) {
|
void _copy_from(const RBSet &p_set) {
|
||||||
clear();
|
clear();
|
||||||
// not the fastest way, but safeset to write.
|
// not the fastest way, but safeset to write.
|
||||||
for (Element *I = p_set.front(); I; I = I->next()) {
|
for (Element *I = p_set.front(); I; I = I->next()) {
|
||||||
|
@ -662,8 +665,12 @@ public:
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool is_empty() const { return _data.size_cache == 0; }
|
inline bool is_empty() const {
|
||||||
inline int size() const { return _data.size_cache; }
|
return _data.size_cache == 0;
|
||||||
|
}
|
||||||
|
inline int size() const {
|
||||||
|
return _data.size_cache;
|
||||||
|
}
|
||||||
|
|
||||||
int calculate_depth() const {
|
int calculate_depth() const {
|
||||||
// used for debug mostly
|
// used for debug mostly
|
||||||
|
@ -687,21 +694,21 @@ public:
|
||||||
_data._free_root();
|
_data._free_root();
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator=(const Set &p_set) {
|
void operator=(const RBSet &p_set) {
|
||||||
_copy_from(p_set);
|
_copy_from(p_set);
|
||||||
}
|
}
|
||||||
|
|
||||||
Set(const Set &p_set) {
|
RBSet(const RBSet &p_set) {
|
||||||
_copy_from(p_set);
|
_copy_from(p_set);
|
||||||
}
|
}
|
||||||
|
|
||||||
_FORCE_INLINE_ Set() {}
|
_FORCE_INLINE_ RBSet() {}
|
||||||
|
|
||||||
~Set() {
|
~RBSet() {
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace godot
|
} // namespace godot
|
||||||
|
|
||||||
#endif // ! SET_HPP
|
#endif // SET_HPP
|
|
@ -285,6 +285,8 @@ public:
|
||||||
bool has_key(const Variant &key, bool *r_valid = nullptr) const;
|
bool has_key(const Variant &key, bool *r_valid = nullptr) const;
|
||||||
static bool has_member(Variant::Type type, const StringName &member);
|
static bool has_member(Variant::Type type, const StringName &member);
|
||||||
|
|
||||||
|
uint32_t hash() const;
|
||||||
|
uint32_t recursive_hash(int recursion_count) const;
|
||||||
bool hash_compare(const Variant &variant) const;
|
bool hash_compare(const Variant &variant) const;
|
||||||
bool booleanize() const;
|
bool booleanize() const;
|
||||||
String stringify() const;
|
String stringify() const;
|
||||||
|
@ -299,6 +301,14 @@ public:
|
||||||
void clear();
|
void clear();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct VariantHasher {
|
||||||
|
static _FORCE_INLINE_ uint32_t hash(const Variant &p_variant) { return p_variant.hash(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VariantComparator {
|
||||||
|
static _FORCE_INLINE_ bool compare(const Variant &p_lhs, const Variant &p_rhs) { return p_lhs.hash_compare(p_rhs); }
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace godot
|
} // namespace godot
|
||||||
|
|
||||||
#endif // ! GODOT_CPP_VARIANT_HPP
|
#endif // ! GODOT_CPP_VARIANT_HPP
|
||||||
|
|
|
@ -629,6 +629,16 @@ bool Variant::has_member(Variant::Type type, const StringName &member) {
|
||||||
return PtrToArg<bool>::convert(&has);
|
return PtrToArg<bool>::convert(&has);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t Variant::hash() const {
|
||||||
|
GDNativeInt hash = internal::gdn_interface->variant_hash(_native_ptr());
|
||||||
|
return PtrToArg<uint32_t>::convert(&hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Variant::recursive_hash(int recursion_count) const {
|
||||||
|
GDNativeInt hash = internal::gdn_interface->variant_recursive_hash(_native_ptr(), recursion_count);
|
||||||
|
return PtrToArg<uint32_t>::convert(&hash);
|
||||||
|
}
|
||||||
|
|
||||||
bool Variant::hash_compare(const Variant &variant) const {
|
bool Variant::hash_compare(const Variant &variant) const {
|
||||||
GDNativeBool compare = internal::gdn_interface->variant_hash_compare(_native_ptr(), variant._native_ptr());
|
GDNativeBool compare = internal::gdn_interface->variant_hash_compare(_native_ptr(), variant._native_ptr());
|
||||||
return PtrToArg<bool>::convert(&compare);
|
return PtrToArg<bool>::convert(&compare);
|
||||||
|
|
Loading…
Reference in New Issue