Added more containers from the pandemonium engine.

This commit is contained in:
Relintai 2023-12-18 21:40:24 +01:00
parent b551dc7ec1
commit 482104191f
12 changed files with 4585 additions and 264 deletions

394
sfw/containers/cowdata.h Normal file
View File

@ -0,0 +1,394 @@
#ifndef COWDATA_H_
#define COWDATA_H_
/*************************************************************************/
/* cowdata.h */
/*************************************************************************/
/* This file is part of: */
/* PANDEMONIUM ENGINE */
/* https://github.com/Relintai/pandemonium_engine */
/*************************************************************************/
/* Copyright (c) 2022-present Péter Magyar. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include <string.h>
#include "core/error/error_macros.h"
#include "core/os/memory.h"
#include "core/os/safe_refcount.h"
template <class T>
class Vector;
class String;
class Char16String;
class CharString;
template <class T, class V>
class VMap;
#if !defined(NO_THREADS)
SAFE_NUMERIC_TYPE_PUN_GUARANTEES(uint32_t)
#endif
template <class T>
class CowData {
template <class TV>
friend class Vector;
friend class String;
friend class Char16String;
friend class CharString;
template <class TV, class VV>
friend class VMap;
private:
mutable T *_ptr;
// 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_ size_t _get_alloc_size(size_t p_elements) const {
//return nearest_power_of_2_templated(p_elements*sizeof(T)+sizeof(SafeRefCount)+sizeof(int));
return 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(_add_overflow) && defined(_mul_overflow)
size_t o;
size_t p;
if (_mul_overflow(p_elements, sizeof(T), &o)) {
*out = 0;
return false;
}
*out = next_power_of_2(o);
if (_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 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 _ptr;
}
_FORCE_INLINE_ const T *ptr() const {
return _ptr;
}
_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 empty() const { return _ptr == nullptr; }
_FORCE_INLINE_ void set(int p_index, const T &p_elem) {
CRASH_BAD_INDEX(p_index, size());
_copy_on_write();
_ptr[p_index] = p_elem;
}
_FORCE_INLINE_ T &get_m(int p_index) {
CRASH_BAD_INDEX(p_index, size());
_copy_on_write();
return _ptr[p_index];
}
_FORCE_INLINE_ const T &get(int p_index) const {
CRASH_BAD_INDEX(p_index, size());
return _ptr[p_index];
}
Error resize(int p_size);
_FORCE_INLINE_ void remove(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;
}
void fill(const T &p_val) {
int len = size();
if (len == 0) {
return;
}
T *p = ptrw();
for (int i = 0; i < len; ++i) {
p[i] = p_val;
}
}
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, true);
}
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 (likely(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), true);
new (mem_new - 2, sizeof(uint32_t), "") 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(_ptr[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, true);
ERR_FAIL_COND_V(!ptr, ERR_OUT_OF_MEMORY);
*(ptr - 1) = 0; //size, currently none
new (ptr - 2, sizeof(uint32_t), "") SafeNumeric<uint32_t>(1); //refcount
_ptr = (T *)ptr;
} else {
uint32_t *_ptrnew = (uint32_t *)Memory::realloc_static(_ptr, alloc_size, true);
ERR_FAIL_COND_V(!_ptrnew, ERR_OUT_OF_MEMORY);
new (_ptrnew - 2, sizeof(uint32_t), "") SafeNumeric<uint32_t>(rc); //refcount
_ptr = (T *)(_ptrnew);
}
}
// construct the newly created elements
if (!HAS_TRIVIAL_CONSTRUCTOR(T)) {
for (int i = *_get_size(); i < p_size; i++) {
memnew_placement(&_ptr[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 = &_ptr[i];
t->~T();
}
}
if (alloc_size != current_alloc_size) {
uint32_t *_ptrnew = (uint32_t *)Memory::realloc_static(_ptr, alloc_size, true);
ERR_FAIL_COND_V(!_ptrnew, ERR_OUT_OF_MEMORY);
new (_ptrnew - 2, sizeof(uint32_t), "") 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() {
_ptr = nullptr;
}
template <class T>
CowData<T>::~CowData() {
_unref(_ptr);
}
#endif /* COW_H_ */

506
sfw/containers/hash_set.h Normal file
View File

@ -0,0 +1,506 @@
#ifndef HASH_SET_H
#define HASH_SET_H
/*************************************************************************/
/* hash_set.h */
/*************************************************************************/
/* This file is part of: */
/* PANDEMONIUM ENGINE */
/* https://github.com/Relintai/pandemonium_engine */
/*************************************************************************/
/* Copyright (c) 2022-present Péter Magyar. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "core/containers/hash_map.h"
#include "core/containers/hashfuncs.h"
#include "core/math/math_funcs.h"
#include "core/os/memory.h"
/**
* 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;
}
static _FORCE_INLINE_ uint32_t _get_probe_length(const uint32_t p_pos, const uint32_t p_hash, const uint32_t p_capacity, const uint64_t p_capacity_inv) {
const uint32_t original_pos = fastmod(p_hash, p_capacity_inv, p_capacity);
return fastmod(p_pos - original_pos + p_capacity, p_capacity_inv, p_capacity);
}
bool _lookup_pos(const TKey &p_key, uint32_t &r_pos) const {
if (keys == nullptr || num_elements == 0) {
return false; // Failed lookups, no elements
}
const uint32_t capacity = hash_table_size_primes[capacity_index];
const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index];
uint32_t hash = _hash(p_key);
uint32_t pos = fastmod(hash, capacity_inv, capacity);
uint32_t distance = 0;
while (true) {
if (hashes[pos] == EMPTY_HASH) {
return false;
}
if (distance > _get_probe_length(pos, hashes[pos], capacity, capacity_inv)) {
return false;
}
if (hashes[pos] == hash && Comparator::compare(keys[hash_to_key[pos]], p_key)) {
r_pos = hash_to_key[pos];
return true;
}
pos = fastmod(pos + 1, capacity_inv, capacity);
distance++;
}
}
uint32_t _insert_with_hash(uint32_t p_hash, uint32_t p_index) {
const uint32_t capacity = hash_table_size_primes[capacity_index];
const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index];
uint32_t hash = p_hash;
uint32_t index = p_index;
uint32_t distance = 0;
uint32_t pos = fastmod(hash, capacity_inv, 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, capacity_inv);
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 = fastmod(pos + 1, capacity_inv, 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 || num_elements == 0) {
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
const uint32_t capacity = hash_table_size_primes[capacity_index];
const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index];
uint32_t next_pos = fastmod(pos + 1, capacity_inv, capacity);
while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity, capacity_inv) != 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 = fastmod(pos + 1, capacity_inv, 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_ const TKey &key() const {
return keys[index];
}
_FORCE_INLINE_ const TKey *key_ptr() const {
return &keys[index];
}
_FORCE_INLINE_ Iterator &next() {
index++;
if (index >= (int32_t)num_keys) {
index = -1;
keys = nullptr;
num_keys = 0;
}
return *this;
}
_FORCE_INLINE_ Iterator &prev() {
index--;
if (index < 0) {
index = -1;
keys = nullptr;
num_keys = 0;
}
return *this;
}
_FORCE_INLINE_ bool valid() const {
return keys != nullptr;
}
_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);
}
}
};
#endif // HASH_SET_H

701
sfw/containers/list.h Normal file
View File

@ -0,0 +1,701 @@
#ifndef GLOBALS_LIST_H
#define GLOBALS_LIST_H
/*************************************************************************/
/* list.h */
/*************************************************************************/
/* This file is part of: */
/* PANDEMONIUM ENGINE */
/* https://github.com/Relintai/pandemonium_engine */
/*************************************************************************/
/* Copyright (c) 2022-present Péter Magyar. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "core/containers/sort_array.h"
#include "core/error/error_macros.h"
#include "core/os/memory.h"
/**
* 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.
*/
template <class T, class A = DefaultAllocator>
class List {
struct _Data;
public:
class Element {
private:
friend class List<T, A>;
T value;
Element *next_ptr;
Element *prev_ptr;
_Data *data;
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() {
next_ptr = nullptr;
prev_ptr = nullptr;
data = nullptr;
};
};
private:
struct _Data {
Element *first;
Element *last;
int size_cache;
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;
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) {
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 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 (I) {
if (c == p_index) {
return I->get();
}
I = I->next();
c++;
}
CRASH_NOW(); // bug!!
}
const T &operator[](int p_index) const {
CRASH_BAD_INDEX(p_index, size());
const Element *I = front();
int c = 0;
while (I) {
if (c == p_index) {
return I->get();
}
I = I->next();
c++;
}
CRASH_NOW(); // bug!!
}
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 invert() {
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 = NULL;
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 = NULL;
current->next_ptr = NULL;
}
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) {
_data = nullptr;
const Element *it = p_list.front();
while (it) {
push_back(it->get());
it = it->next();
}
}
List() {
_data = nullptr;
};
~List() {
clear();
if (_data) {
ERR_FAIL_COND(_data->size_cache);
memdelete_allocator<_Data, A>(_data);
}
};
};
#endif

View File

@ -0,0 +1,323 @@
#ifndef LOCAL_VECTOR_H
#define LOCAL_VECTOR_H
/*************************************************************************/
/* local_vector.h */
/*************************************************************************/
/* This file is part of: */
/* PANDEMONIUM ENGINE */
/* https://github.com/Relintai/pandemonium_engine */
/*************************************************************************/
/* Copyright (c) 2022-present Péter Magyar. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "core/containers/pool_vector.h"
#include "core/containers/sort_array.h"
#include "core/containers/vector.h"
#include "core/error/error_macros.h"
#include "core/os/memory.h"
template <class T, class U = uint32_t, bool force_trivial = false>
class LocalVector {
protected:
U count = 0;
U capacity = 0;
T *data = nullptr;
public:
T *ptr() {
return data;
}
const T *ptr() const {
return data;
}
_FORCE_INLINE_ void push_back(T p_elem) {
if (unlikely(count == capacity)) {
if (capacity == 0) {
capacity = 1;
} else {
capacity <<= 1;
}
data = (T *)memrealloc(data, capacity * sizeof(T));
CRASH_COND_MSG(!data, "Out of memory");
}
if (!HAS_TRIVIAL_CONSTRUCTOR(T) && !force_trivial) {
memnew_placement(&data[count++], T(p_elem));
} else {
data[count++] = p_elem;
}
}
void remove(U p_index) {
ERR_FAIL_UNSIGNED_INDEX(p_index, count);
count--;
for (U i = p_index; i < count; i++) {
data[i] = data[i + 1];
}
if (!HAS_TRIVIAL_DESTRUCTOR(T) && !force_trivial) {
data[count].~T();
}
}
// Removes the item copying the last value into the position of the one to
// remove. It's generally faster than `remove`.
void remove_unordered(U p_index) {
ERR_FAIL_INDEX(p_index, count);
count--;
if (count > p_index) {
data[p_index] = data[count];
}
if (!HAS_TRIVIAL_DESTRUCTOR(T) && !force_trivial) {
data[count].~T();
}
}
_FORCE_INLINE_ bool erase(const T &p_val) {
int64_t idx = find(p_val);
if (idx >= 0) {
remove(idx);
return true;
}
return false;
}
U erase_multiple_unordered(const T &p_val) {
U from = 0;
U count = 0;
while (true) {
int64_t idx = find(p_val, from);
if (idx == -1) {
break;
}
remove_unordered(idx);
from = idx;
count++;
}
return count;
}
void invert() {
for (U i = 0; i < count / 2; i++) {
SWAP(data[i], data[count - i - 1]);
}
}
_FORCE_INLINE_ void clear() { resize(0); }
_FORCE_INLINE_ void reset() {
clear();
if (data) {
memfree(data);
data = nullptr;
capacity = 0;
}
}
_FORCE_INLINE_ bool empty() const { return count == 0; }
_FORCE_INLINE_ U get_capacity() const { return capacity; }
_FORCE_INLINE_ void reserve(U p_size, bool p_allow_shrink = false) {
p_size = nearest_power_of_2_templated(p_size);
if (!p_allow_shrink ? p_size > capacity : ((p_size >= count) && (p_size != capacity))) {
capacity = p_size;
data = (T *)memrealloc(data, capacity * sizeof(T));
CRASH_COND_MSG(!data, "Out of memory");
}
}
_FORCE_INLINE_ U size() const { return count; }
void resize(U p_size) {
if (p_size < count) {
if (!HAS_TRIVIAL_DESTRUCTOR(T) && !force_trivial) {
for (U i = p_size; i < count; i++) {
data[i].~T();
}
}
count = p_size;
} else if (p_size > count) {
if (unlikely(p_size > capacity)) {
if (capacity == 0) {
capacity = 1;
}
while (capacity < p_size) {
capacity <<= 1;
}
data = (T *)memrealloc(data, capacity * sizeof(T));
CRASH_COND_MSG(!data, "Out of memory");
}
if (!HAS_TRIVIAL_CONSTRUCTOR(T) && !force_trivial) {
for (U i = count; i < p_size; i++) {
memnew_placement(&data[i], T);
}
}
count = p_size;
}
}
_FORCE_INLINE_ const T &operator[](U p_index) const {
CRASH_BAD_UNSIGNED_INDEX(p_index, count);
return data[p_index];
}
_FORCE_INLINE_ T &operator[](U p_index) {
CRASH_BAD_UNSIGNED_INDEX(p_index, count);
return data[p_index];
}
void fill(T p_val) {
for (U i = 0; i < count; i++) {
data[i] = p_val;
}
}
void insert(U p_pos, T p_val) {
ERR_FAIL_UNSIGNED_INDEX(p_pos, count + 1);
if (p_pos == count) {
push_back(p_val);
} else {
resize(count + 1);
for (U i = count - 1; i > p_pos; i--) {
data[i] = data[i - 1];
}
data[p_pos] = p_val;
}
}
int64_t find(const T &p_val, U p_from = 0) const {
for (U i = p_from; i < count; i++) {
if (data[i] == p_val) {
return int64_t(i);
}
}
return -1;
}
template <class C>
void sort_custom() {
U len = count;
if (len == 0) {
return;
}
SortArray<T, C> sorter;
sorter.sort(data, len);
}
void sort() {
sort_custom<_DefaultComparator<T>>();
}
void ordered_insert(T p_val) {
U i;
for (i = 0; i < count; i++) {
if (p_val < data[i]) {
break;
}
}
insert(i, p_val);
}
operator Vector<T>() const {
Vector<T> ret;
ret.resize(size());
T *w = ret.ptrw();
memcpy(w, data, sizeof(T) * count);
return ret;
}
operator PoolVector<T>() const {
PoolVector<T> pl;
if (size()) {
pl.resize(size());
typename PoolVector<T>::Write w = pl.write();
T *dest = w.ptr();
memcpy(dest, data, sizeof(T) * count);
}
return pl;
}
Vector<uint8_t> to_byte_array() const { //useful to pass stuff to gpu or variant
Vector<uint8_t> ret;
ret.resize(count * sizeof(T));
uint8_t *w = ret.ptrw();
memcpy(w, data, sizeof(T) * count);
return ret;
}
_FORCE_INLINE_ LocalVector() {}
_FORCE_INLINE_ LocalVector(const LocalVector &p_from) {
resize(p_from.size());
for (U i = 0; i < p_from.count; i++) {
data[i] = p_from.data[i];
}
}
LocalVector(const Vector<T> &p_from) {
resize(p_from.size());
for (U i = 0; i < count; i++) {
data[i] = p_from[i];
}
}
LocalVector(const PoolVector<T> &p_from) {
resize(p_from.size());
typename PoolVector<T>::Read r = p_from.read();
for (U i = 0; i < count; i++) {
data[i] = r[i];
}
}
inline LocalVector &operator=(const LocalVector &p_from) {
resize(p_from.size());
for (U i = 0; i < p_from.count; i++) {
data[i] = p_from.data[i];
}
return *this;
}
inline LocalVector &operator=(const Vector<T> &p_from) {
resize(p_from.size());
for (U i = 0; i < count; i++) {
data[i] = p_from[i];
}
return *this;
}
inline LocalVector &operator=(const PoolVector<T> &p_from) {
resize(p_from.size());
typename PoolVector<T>::Read r = p_from.read();
for (U i = 0; i < count; i++) {
data[i] = r[i];
}
return *this;
}
_FORCE_INLINE_ ~LocalVector() {
if (data) {
reset();
}
}
};
// Integer default version
template <class T, class I = int32_t, bool force_trivial = false>
class LocalVectori : public LocalVector<T, I, force_trivial> {
};
#endif // LOCAL_VECTOR_H

679
sfw/containers/rb_map.h Normal file
View File

@ -0,0 +1,679 @@
#ifndef RB_MAP_H
#define RB_MAP_H
/*************************************************************************/
/* rb_map.h */
/*************************************************************************/
/* This file is part of: */
/* PANDEMONIUM ENGINE */
/* https://github.com/Relintai/pandemonium_engine */
/*************************************************************************/
/* Copyright (c) 2022-present Péter Magyar. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "core/error/error_macros.h"
#include "core/os/memory.h"
// based on the very nice implementation of rb-trees by:
// https://web.archive.org/web/20120507164830/http://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 RBMap {
enum Color {
RED,
BLACK
};
struct _Data;
public:
class Element {
private:
friend class RBMap<K, V, C, A>;
int color;
Element *right;
Element *left;
Element *parent;
Element *_next;
Element *_prev;
K _key;
V _value;
//_Data *data;
public:
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 _key;
};
V &value() {
return _value;
};
const V &value() const {
return _value;
};
V &get() {
return _value;
};
const V &get() const {
return _value;
};
Element() {
color = RED;
right = nullptr;
left = nullptr;
parent = nullptr;
_next = nullptr;
_prev = nullptr;
};
};
private:
struct _Data {
Element *_root;
Element *_nil;
int size_cache;
_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
_root = nullptr;
size_cache = 0;
}
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 K &p_key) const {
Element *node = _data._root->left;
C less;
while (node != _data._nil) {
if (less(p_key, node->_key)) {
node = node->left;
} else if (less(node->_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->_key)) {
node = node->left;
} else if (less(node->_key, p_key)) {
node = node->right;
} else {
return node; // found
}
}
if (prev == nullptr) {
return nullptr; // tree empty
}
if (less(p_key, prev->_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->_key)) {
node = node->left;
} else if (less(node->_key, p_key)) {
node = node->right;
} else {
node->_value = p_value;
return node; // Return existing node with new value
}
}
Element *new_node = memnew_allocator(Element, A);
new_node->parent = new_parent;
new_node->right = _data._nil;
new_node->left = _data._nil;
new_node->_key = p_key;
new_node->_value = p_value;
//new_node->data=_data;
if (new_parent == _data._root || less(p_key, new_parent->_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 RBMap &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 NULL;
}
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->_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->_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 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 RBMap &p_map) {
_copy_from(p_map);
}
RBMap(const RBMap &p_map) {
_copy_from(p_map);
}
_FORCE_INLINE_ RBMap() {
}
~RBMap() {
clear();
}
};
#endif

633
sfw/containers/rb_set.h Normal file
View File

@ -0,0 +1,633 @@
#ifndef RB_SET_H
#define RB_SET_H
/*************************************************************************/
/* rb_set.h */
/*************************************************************************/
/* This file is part of: */
/* PANDEMONIUM ENGINE */
/* https://github.com/Relintai/pandemonium_engine */
/*************************************************************************/
/* Copyright (c) 2022-present Péter Magyar. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "core/os/memory.h"
#include "core/typedefs.h"
// based on the very nice implementation of rb-trees by:
// https://web.archive.org/web/20120507164830/http://web.mit.edu/~emin/www/source_code/red_black_tree/index.html
template <class T, class C = Comparator<T>, class A = DefaultAllocator>
class RBSet {
enum Color {
RED,
BLACK
};
struct _Data;
public:
class Element {
private:
friend class RBSet<T, C, A>;
int color;
Element *right;
Element *left;
Element *parent;
Element *_next;
Element *_prev;
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;
}
const T &get() const {
return value;
};
Element() {
color = RED;
right = nullptr;
left = nullptr;
parent = nullptr;
_next = nullptr;
_prev = nullptr;
};
};
private:
struct _Data {
Element *_root;
Element *_nil;
int size_cache;
_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
_root = nullptr;
size_cache = 0;
}
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 RBSet &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 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 RBSet &p_set) {
_copy_from(p_set);
}
RBSet(const RBSet &p_set) {
_copy_from(p_set);
}
_FORCE_INLINE_ RBSet() {
}
~RBSet() {
clear();
}
};
#endif

View File

@ -0,0 +1,223 @@
#ifndef RINGBUFFER_H
#define RINGBUFFER_H
/*************************************************************************/
/* ring_buffer.h */
/*************************************************************************/
/* This file is part of: */
/* PANDEMONIUM ENGINE */
/* https://github.com/Relintai/pandemonium_engine */
/*************************************************************************/
/* Copyright (c) 2022-present Péter Magyar. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "core/containers/vector.h"
template <typename T>
class RingBuffer {
Vector<T> data;
int read_pos;
int write_pos;
int size_mask;
inline int inc(int &p_var, int p_size) const {
int ret = p_var;
p_var += p_size;
p_var = p_var & size_mask;
return ret;
};
public:
T read() {
ERR_FAIL_COND_V(space_left() < 1, T());
return data.ptr()[inc(read_pos, 1)];
};
int read(T *p_buf, int p_size, bool p_advance = true) {
int left = data_left();
p_size = MIN(left, p_size);
int pos = read_pos;
int to_read = p_size;
int dst = 0;
while (to_read) {
int end = pos + to_read;
end = MIN(end, size());
int total = end - pos;
const T *read = data.ptr();
for (int i = 0; i < total; i++) {
p_buf[dst++] = read[pos + i];
};
to_read -= total;
pos = 0;
};
if (p_advance) {
inc(read_pos, p_size);
};
return p_size;
};
int copy(T *p_buf, int p_offset, int p_size) const {
int left = data_left();
if ((p_offset + p_size) > left) {
p_size -= left - p_offset;
if (p_size <= 0) {
return 0;
}
}
p_size = MIN(left, p_size);
int pos = read_pos;
inc(pos, p_offset);
int to_read = p_size;
int dst = 0;
while (to_read) {
int end = pos + to_read;
end = MIN(end, size());
int total = end - pos;
for (int i = 0; i < total; i++) {
p_buf[dst++] = data[pos + i];
};
to_read -= total;
pos = 0;
};
return p_size;
};
int find(const T &t, int p_offset, int p_max_size) const {
int left = data_left();
if ((p_offset + p_max_size) > left) {
p_max_size -= left - p_offset;
if (p_max_size <= 0) {
return 0;
}
}
p_max_size = MIN(left, p_max_size);
int pos = read_pos;
inc(pos, p_offset);
int to_read = p_max_size;
while (to_read) {
int end = pos + to_read;
end = MIN(end, size());
int total = end - pos;
for (int i = 0; i < total; i++) {
if (data[pos + i] == t) {
return i + (p_max_size - to_read);
}
};
to_read -= total;
pos = 0;
}
return -1;
}
inline int advance_read(int p_n) {
p_n = MIN(p_n, data_left());
inc(read_pos, p_n);
return p_n;
};
inline int decrease_write(int p_n) {
p_n = MIN(p_n, data_left());
inc(write_pos, size_mask + 1 - p_n);
return p_n;
}
Error write(const T &p_v) {
ERR_FAIL_COND_V(space_left() < 1, FAILED);
data.write[inc(write_pos, 1)] = p_v;
return OK;
};
int write(const T *p_buf, int p_size) {
int left = space_left();
p_size = MIN(left, p_size);
int pos = write_pos;
int to_write = p_size;
int src = 0;
while (to_write) {
int end = pos + to_write;
end = MIN(end, size());
int total = end - pos;
for (int i = 0; i < total; i++) {
data.write[pos + i] = p_buf[src++];
};
to_write -= total;
pos = 0;
};
inc(write_pos, p_size);
return p_size;
};
inline int space_left() const {
int left = read_pos - write_pos;
if (left < 0) {
return size() + left - 1;
};
if (left == 0) {
return size() - 1;
};
return left - 1;
};
inline int data_left() const {
return size() - space_left() - 1;
};
inline int size() const {
return data.size();
};
inline void clear() {
read_pos = 0;
write_pos = 0;
}
void resize(int p_power) {
int old_size = size();
int new_size = 1 << p_power;
int mask = new_size - 1;
data.resize(1 << p_power);
if (old_size < new_size && read_pos > write_pos) {
for (int i = 0; i < write_pos; i++) {
data.write[(old_size + i) & mask] = data[i];
};
write_pos = (old_size + write_pos) & mask;
} else {
read_pos = read_pos & mask;
write_pos = write_pos & mask;
};
size_mask = mask;
};
RingBuffer<T>(int p_power = 0) {
read_pos = 0;
write_pos = 0;
resize(p_power);
};
~RingBuffer<T>(){};
};
#endif

287
sfw/containers/rvector.h Normal file
View File

@ -0,0 +1,287 @@
#ifndef VECTOR_H
#define VECTOR_H
#include "core/error_macros.h"
template <class T>
class Vector {
public:
void push_back(const T &element);
void pop_back();
void remove(const int index);
void remove_keep_order(const int index);
void erase(const T &element);
void clear();
bool empty() const;
T get(const int index);
const T &get(const int index) const;
void set(const int index, const T &value);
void swap(const int index1, const int index2);
void sort_inc();
void sort_dec();
int size() const;
int capacity() const;
void ensure_capacity(const int capacity);
void resize(const int s);
void append_array(const Vector<T> &other);
int find(const T &val) const;
T *dataw();
const T *data() const;
const T &operator[](const int index) const;
T &operator[](const int index);
Vector &operator=(const Vector &other);
Vector();
Vector(int prealloc);
Vector(int prealloc, int grow_by);
Vector(const Vector &other);
~Vector();
private:
T *_data;
int _actual_size;
int _size;
int _grow_by;
};
template <class T>
void Vector<T>::push_back(const T &element) {
ensure_capacity(_size + 1);
_data[_size++] = element;
}
template <class T>
void Vector<T>::pop_back() {
if (_size == 0) {
return;
}
--_size;
}
template <class T>
void Vector<T>::remove(const int index) {
_data[index] = _data[_size - 1];
--_size;
}
template <class T>
void Vector<T>::remove_keep_order(const int index) {
--_size;
for (int i = index; i < _size; ++i) {
_data[i] = _data[i + 1];
}
}
template <class T>
void Vector<T>::erase(const T &element) {
int index = find(element);
if (index != -1) {
remove(index);
}
}
template <class T>
void Vector<T>::clear() {
_size = 0;
}
template <class T>
bool Vector<T>::empty() const {
return _size == 0;
}
template <class T>
T Vector<T>::get(const int index) {
return _data[index];
}
template <class T>
const T &Vector<T>::get(const int index) const {
return _data[index];
}
template <class T>
void Vector<T>::set(const int index, const T &value) {
_data[index] = value;
}
template <class T>
void Vector<T>::swap(const int index1, const int index2) {
T e = _data[index1];
_data[index1] = _data[index2];
_data[index2] = e;
}
template <class T>
void Vector<T>::sort_inc() {
for (int i = 0; i < _size; ++i) {
for (int j = i + 1; j < _size; ++j) {
if (_data[j] < _data[i]) {
swap(i, j);
}
}
}
}
template <class T>
void Vector<T>::sort_dec() {
for (int i = 0; i < _size; ++i) {
for (int j = i + 1; j < _size; ++j) {
if (_data[j] > _data[i]) {
swap(i, j);
}
}
}
}
template <class T>
int Vector<T>::size() const {
return _size;
}
template <class T>
int Vector<T>::capacity() const {
return _actual_size;
}
template <class T>
void Vector<T>::ensure_capacity(const int capacity) {
if (capacity <= _actual_size) {
return;
}
int tsize = capacity + _grow_by;
T *nd = new T[tsize];
if (_data) {
for (int i = 0; i < _size; ++i) {
nd[i] = _data[i];
}
delete[] _data;
}
_data = nd;
_actual_size = tsize;
}
template <class T>
void Vector<T>::resize(const int s) {
ensure_capacity(s);
_size = s;
}
template <class T>
void Vector<T>::append_array(const Vector<T> &other) {
ensure_capacity(_size + other._size);
for (int i = 0; i < other._size; ++i) {
_data[_size++] = other._data[i];
}
}
template <class T>
int Vector<T>::find(const T &val) const {
for (int i = 0; i < _size; ++i) {
if (_data[i] == val) {
return i;
}
}
return -1;
}
template <class T>
T *Vector<T>::dataw() {
return _data;
}
template <class T>
const T *Vector<T>::data() const {
return _data;
}
template <class T>
const T &Vector<T>::operator[](const int index) const {
return _data[index];
}
template <class T>
T &Vector<T>::operator[](const int index) {
return _data[index];
}
template <class T>
Vector<T> &Vector<T>::operator=(const Vector<T> &other) {
resize(0);
ensure_capacity(other.size());
append_array(other);
return *this;
}
template <class T>
Vector<T>::Vector() {
_data = nullptr;
_actual_size = 0;
_size = 0;
_grow_by = 100;
}
template <class T>
Vector<T>::Vector(int prealloc) {
_data = nullptr;
_actual_size = 0;
_size = 0;
_grow_by = 100;
ensure_capacity(prealloc);
}
template <class T>
Vector<T>::Vector(int prealloc, int grow_by) {
_data = nullptr;
_actual_size = 0;
_size = 0;
_grow_by = grow_by;
ensure_capacity(prealloc);
}
template <class T>
Vector<T>::Vector(const Vector<T> &other) {
_actual_size = other._actual_size;
_size = other._size;
_grow_by = other._grow_by;
if (other._data) {
_data = new T[_actual_size];
for (int i = 0; i < _size; ++i) {
_data[i] = other._data[i];
}
}
}
template <class T>
Vector<T>::~Vector() {
if (_data) {
delete[] _data;
_data = nullptr;
}
}
#endif

View File

@ -0,0 +1,319 @@
#ifndef TIGHT_LOCAL_VECTOR_H
#define TIGHT_LOCAL_VECTOR_H
/*************************************************************************/
/* tight_local_vector.h */
/*************************************************************************/
/* This file is part of: */
/* PANDEMONIUM ENGINE */
/* https://github.com/Relintai/pandemonium_engine */
/*************************************************************************/
/* Copyright (c) 2022-present Péter Magyar. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "core/containers/pool_vector.h"
#include "core/containers/sort_array.h"
#include "core/containers/vector.h"
#include "core/error/error_macros.h"
#include "core/os/memory.h"
// It grows strictly as much as needed. (The vanilla LocalVector is what you want in most cases).
template <class T, class U = uint32_t, bool force_trivial = false>
class TightLocalVector {
private:
U count = 0;
U capacity = 0;
T *data = nullptr;
public:
T *ptr() {
return data;
}
const T *ptr() const {
return data;
}
_FORCE_INLINE_ void push_back(T p_elem) {
if (unlikely(count == capacity)) {
if (capacity == 0) {
capacity = 1;
} else {
capacity <<= 1;
}
data = (T *)memrealloc(data, capacity * sizeof(T));
CRASH_COND_MSG(!data, "Out of memory");
}
if constexpr (!HAS_TRIVIAL_CONSTRUCTOR(T) && !force_trivial) {
memnew_placement(&data[count++], T(p_elem));
} else {
data[count++] = p_elem;
}
}
void remove(U p_index) {
ERR_FAIL_UNSIGNED_INDEX(p_index, count);
count--;
for (U i = p_index; i < count; i++) {
data[i] = data[i + 1];
}
if constexpr (!HAS_TRIVIAL_DESTRUCTOR(T) && !force_trivial) {
data[count].~T();
}
}
/// Removes the item copying the last value into the position of the one to
/// remove. It's generally faster than `remove`.
void remove_unordered(U p_index) {
ERR_FAIL_INDEX(p_index, count);
count--;
if (count > p_index) {
data[p_index] = data[count];
}
if constexpr (!HAS_TRIVIAL_DESTRUCTOR(T) && !force_trivial) {
data[count].~T();
}
}
void erase(const T &p_val) {
int64_t idx = find(p_val);
if (idx >= 0) {
remove(idx);
}
}
U erase_multiple_unordered(const T &p_val) {
U from = 0;
U count = 0;
while (true) {
int64_t idx = find(p_val, from);
if (idx == -1) {
break;
}
remove_unordered(idx);
from = idx;
count++;
}
return count;
}
void invert() {
for (U i = 0; i < count / 2; i++) {
SWAP(data[i], data[count - i - 1]);
}
}
_FORCE_INLINE_ void clear() { resize(0); }
_FORCE_INLINE_ void reset() {
clear();
if (data) {
memfree(data);
data = nullptr;
capacity = 0;
}
}
_FORCE_INLINE_ bool empty() const { return count == 0; }
_FORCE_INLINE_ U get_capacity() const { return capacity; }
_FORCE_INLINE_ void reserve(U p_size) {
if (p_size > capacity) {
capacity = p_size;
data = (T *)memrealloc(data, capacity * sizeof(T));
CRASH_COND_MSG(!data, "Out of memory");
}
}
_FORCE_INLINE_ U size() const { return count; }
void resize(U p_size) {
if (p_size < count) {
if (!HAS_TRIVIAL_DESTRUCTOR(T) && !force_trivial) {
for (U i = p_size; i < count; i++) {
data[i].~T();
}
}
count = p_size;
} else if (p_size > count) {
if (unlikely(p_size > capacity)) {
if (capacity == 0) {
capacity = 1;
}
while (capacity < p_size) {
capacity <<= 1;
}
data = (T *)memrealloc(data, capacity * sizeof(T));
CRASH_COND_MSG(!data, "Out of memory");
}
if (!HAS_TRIVIAL_CONSTRUCTOR(T) && !force_trivial) {
for (U i = count; i < p_size; i++) {
memnew_placement(&data[i], T);
}
}
count = p_size;
}
}
_FORCE_INLINE_ const T &operator[](U p_index) const {
CRASH_BAD_UNSIGNED_INDEX(p_index, count);
return data[p_index];
}
_FORCE_INLINE_ T &operator[](U p_index) {
CRASH_BAD_UNSIGNED_INDEX(p_index, count);
return data[p_index];
}
void fill(T p_val) {
for (U i = 0; i < count; i++) {
data[i] = p_val;
}
}
void insert(U p_pos, T p_val) {
ERR_FAIL_UNSIGNED_INDEX(p_pos, count + 1);
if (p_pos == count) {
push_back(p_val);
} else {
resize(count + 1);
for (U i = count - 1; i > p_pos; i--) {
data[i] = data[i - 1];
}
data[p_pos] = p_val;
}
}
int64_t find(const T &p_val, U p_from = 0) const {
for (U i = p_from; i < count; i++) {
if (data[i] == p_val) {
return int64_t(i);
}
}
return -1;
}
template <class C>
void sort_custom() {
U len = count;
if (len == 0) {
return;
}
SortArray<T, C> sorter;
sorter.sort(data, len);
}
void sort() {
sort_custom<_DefaultComparator<T>>();
}
void ordered_insert(T p_val) {
U i;
for (i = 0; i < count; i++) {
if (p_val < data[i]) {
break;
}
}
insert(i, p_val);
}
operator Vector<T>() const {
Vector<T> ret;
ret.resize(size());
T *w = ret.ptrw();
memcpy(w, data, sizeof(T) * count);
return ret;
}
operator PoolVector<T>() const {
PoolVector<T> pl;
if (size()) {
pl.resize(size());
typename PoolVector<T>::Write w = pl.write();
T *dest = w.ptr();
memcpy(dest, data, sizeof(T) * count);
}
return pl;
}
Vector<uint8_t> to_byte_array() const { //useful to pass stuff to gpu or variant
Vector<uint8_t> ret;
ret.resize(count * sizeof(T));
uint8_t *w = ret.ptrw();
memcpy(w, data, sizeof(T) * count);
return ret;
}
_FORCE_INLINE_ TightLocalVector() {}
_FORCE_INLINE_ TightLocalVector(const TightLocalVector &p_from) {
resize(p_from.size());
for (U i = 0; i < p_from.count; i++) {
data[i] = p_from.data[i];
}
}
TightLocalVector(const Vector<T> &p_from) {
resize(p_from.size());
for (U i = 0; i < count; i++) {
data[i] = p_from[i];
}
}
TightLocalVector(const PoolVector<T> &p_from) {
resize(p_from.size());
typename PoolVector<T>::Read r = p_from.read();
for (U i = 0; i < count; i++) {
data[i] = r[i];
}
}
inline void operator=(const TightLocalVector &p_from) {
resize(p_from.size());
for (U i = 0; i < p_from.count; i++) {
data[i] = p_from.data[i];
}
}
inline void operator=(const Vector<T> &p_from) {
resize(p_from.size());
for (U i = 0; i < count; i++) {
data[i] = p_from[i];
}
}
inline TightLocalVector &operator=(const PoolVector<T> &p_from) {
resize(p_from.size());
typename PoolVector<T>::Read r = p_from.read();
for (U i = 0; i < count; i++) {
data[i] = r[i];
}
return *this;
}
_FORCE_INLINE_ ~TightLocalVector() {
if (data) {
reset();
}
}
};
// Integer default version
template <class T, class I = int32_t, bool force_trivial = false>
class TightLocalVectori : public TightLocalVector<T, I, force_trivial> {
};
#endif // TIGHT_LOCAL_VECTOR_H

View File

@ -1,287 +1,198 @@
#ifndef VECTOR_H
#define VECTOR_H
#include "core/error_macros.h"
/*************************************************************************/
/* vector.h */
/*************************************************************************/
/* This file is part of: */
/* PANDEMONIUM ENGINE */
/* https://github.com/Relintai/pandemonium_engine */
/*************************************************************************/
/* Copyright (c) 2022-present Péter Magyar. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
/**
* @class Vector
* @author Juan Linietsky
* Vector container. Regular Vector Container. Use with care and for smaller arrays when possible. Use PoolVector for large arrays.
*/
#include "core/containers/cowdata.h"
#include "core/containers/sort_array.h"
#include "core/error/error_macros.h"
#include "core/os/memory.h"
template <class T>
class Vector {
class VectorWriteProxy {
public:
void push_back(const T &element);
void pop_back();
void remove(const int index);
void remove_keep_order(const int index);
void erase(const T &element);
void clear();
bool empty() const;
T get(const int index);
const T &get(const int index) const;
void set(const int index, const T &value);
void swap(const int index1, const int index2);
_FORCE_INLINE_ T &operator[](int p_index) {
CRASH_BAD_INDEX(p_index, ((Vector<T> *)(this))->_cowdata.size());
void sort_inc();
void sort_dec();
int size() const;
int capacity() const;
void ensure_capacity(const int capacity);
void resize(const int s);
void append_array(const Vector<T> &other);
int find(const T &val) const;
T *dataw();
const T *data() const;
const T &operator[](const int index) const;
T &operator[](const int index);
Vector &operator=(const Vector &other);
Vector();
Vector(int prealloc);
Vector(int prealloc, int grow_by);
Vector(const Vector &other);
~Vector();
private:
T *_data;
int _actual_size;
int _size;
int _grow_by;
return ((Vector<T> *)(this))->_cowdata.ptrw()[p_index];
}
};
template <class T>
void Vector<T>::push_back(const T &element) {
ensure_capacity(_size + 1);
class Vector {
friend class VectorWriteProxy<T>;
_data[_size++] = element;
public:
VectorWriteProxy<T> write;
private:
CowData<T> _cowdata;
public:
bool push_back(T p_elem);
void remove(int p_index) { _cowdata.remove(p_index); }
_FORCE_INLINE_ bool erase(const T &p_val) {
int idx = find(p_val);
if (idx >= 0) {
remove(idx);
return true;
}
return false;
};
void invert();
_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 empty() const { return _cowdata.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); }
_FORCE_INLINE_ void fill(const T &p_val) { _cowdata.fill(p_val); }
void append_array(Vector<T> p_other);
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>>();
}
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);
}
_FORCE_INLINE_ Vector() {}
_FORCE_INLINE_ Vector(const Vector &p_from) { _cowdata._ref(p_from._cowdata); }
inline Vector &operator=(const Vector &p_from) {
_cowdata._ref(p_from._cowdata);
return *this;
}
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 = INT32_MAX) const {
Vector<T> result;
const int s = size();
int begin = CLAMP(p_begin, -s, s);
if (begin < 0) {
begin += s;
}
int end = 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;
}
_FORCE_INLINE_ ~Vector() {}
};
template <class T>
void Vector<T>::invert() {
for (int i = 0; i < size() / 2; i++) {
T *p = ptrw();
SWAP(p[i], p[size() - i - 1]);
}
}
template <class T>
void Vector<T>::pop_back() {
if (_size == 0) {
void Vector<T>::append_array(Vector<T> p_other) {
const int ds = p_other.size();
if (ds == 0) {
return;
}
--_size;
}
template <class T>
void Vector<T>::remove(const int index) {
_data[index] = _data[_size - 1];
--_size;
}
template <class T>
void Vector<T>::remove_keep_order(const int index) {
--_size;
for (int i = index; i < _size; ++i) {
_data[i] = _data[i + 1];
const int bs = size();
resize(bs + ds);
for (int i = 0; i < ds; ++i) {
ptrw()[bs + i] = p_other[i];
}
}
template <class T>
void Vector<T>::erase(const T &element) {
int index = find(element);
bool Vector<T>::push_back(T p_elem) {
Error err = resize(size() + 1);
ERR_FAIL_COND_V(err, true);
set(size() - 1, p_elem);
if (index != -1) {
remove(index);
}
return false;
}
template <class T>
void Vector<T>::clear() {
_size = 0;
}
template <class T>
bool Vector<T>::empty() const {
return _size == 0;
}
template <class T>
T Vector<T>::get(const int index) {
return _data[index];
}
template <class T>
const T &Vector<T>::get(const int index) const {
return _data[index];
}
template <class T>
void Vector<T>::set(const int index, const T &value) {
_data[index] = value;
}
template <class T>
void Vector<T>::swap(const int index1, const int index2) {
T e = _data[index1];
_data[index1] = _data[index2];
_data[index2] = e;
}
template <class T>
void Vector<T>::sort_inc() {
for (int i = 0; i < _size; ++i) {
for (int j = i + 1; j < _size; ++j) {
if (_data[j] < _data[i]) {
swap(i, j);
}
}
}
}
template <class T>
void Vector<T>::sort_dec() {
for (int i = 0; i < _size; ++i) {
for (int j = i + 1; j < _size; ++j) {
if (_data[j] > _data[i]) {
swap(i, j);
}
}
}
}
template <class T>
int Vector<T>::size() const {
return _size;
}
template <class T>
int Vector<T>::capacity() const {
return _actual_size;
}
template <class T>
void Vector<T>::ensure_capacity(const int capacity) {
if (capacity <= _actual_size) {
return;
}
int tsize = capacity + _grow_by;
T *nd = new T[tsize];
if (_data) {
for (int i = 0; i < _size; ++i) {
nd[i] = _data[i];
}
delete[] _data;
}
_data = nd;
_actual_size = tsize;
}
template <class T>
void Vector<T>::resize(const int s) {
ensure_capacity(s);
_size = s;
}
template <class T>
void Vector<T>::append_array(const Vector<T> &other) {
ensure_capacity(_size + other._size);
for (int i = 0; i < other._size; ++i) {
_data[_size++] = other._data[i];
}
}
template <class T>
int Vector<T>::find(const T &val) const {
for (int i = 0; i < _size; ++i) {
if (_data[i] == val) {
return i;
}
}
return -1;
}
template <class T>
T *Vector<T>::dataw() {
return _data;
}
template <class T>
const T *Vector<T>::data() const {
return _data;
}
template <class T>
const T &Vector<T>::operator[](const int index) const {
return _data[index];
}
template <class T>
T &Vector<T>::operator[](const int index) {
return _data[index];
}
template <class T>
Vector<T> &Vector<T>::operator=(const Vector<T> &other) {
resize(0);
ensure_capacity(other.size());
append_array(other);
return *this;
}
template <class T>
Vector<T>::Vector() {
_data = nullptr;
_actual_size = 0;
_size = 0;
_grow_by = 100;
}
template <class T>
Vector<T>::Vector(int prealloc) {
_data = nullptr;
_actual_size = 0;
_size = 0;
_grow_by = 100;
ensure_capacity(prealloc);
}
template <class T>
Vector<T>::Vector(int prealloc, int grow_by) {
_data = nullptr;
_actual_size = 0;
_size = 0;
_grow_by = grow_by;
ensure_capacity(prealloc);
}
template <class T>
Vector<T>::Vector(const Vector<T> &other) {
_actual_size = other._actual_size;
_size = other._size;
_grow_by = other._grow_by;
if (other._data) {
_data = new T[_actual_size];
for (int i = 0; i < _size; ++i) {
_data[i] = other._data[i];
}
}
}
template <class T>
Vector<T>::~Vector() {
if (_data) {
delete[] _data;
_data = nullptr;
}
}
#endif
#endif

203
sfw/containers/vmap.h Normal file
View File

@ -0,0 +1,203 @@
#ifndef VMAP_H
#define VMAP_H
/*************************************************************************/
/* vmap.h */
/*************************************************************************/
/* This file is part of: */
/* PANDEMONIUM ENGINE */
/* https://github.com/Relintai/pandemonium_engine */
/*************************************************************************/
/* Copyright (c) 2022-present Péter Magyar. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "core/containers/cowdata.h"
#include "core/typedefs.h"
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.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.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(pos);
}
int find(const T &p_val) const {
return _find_exact(p_val);
}
int find_nearest(const T &p_val) const {
if (_cowdata.empty()) {
return -1;
}
bool exact;
return _find(p_val, exact);
}
_FORCE_INLINE_ int size() const { return _cowdata.size(); }
_FORCE_INLINE_ bool empty() const { return _cowdata.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 VMap &operator=(const VMap &p_from) {
_cowdata._ref(p_from._cowdata);
return *this;
}
};
#endif // VMAP_H

142
sfw/containers/vset.h Normal file
View File

@ -0,0 +1,142 @@
#ifndef VSET_H
#define VSET_H
/*************************************************************************/
/* vset.h */
/*************************************************************************/
/* This file is part of: */
/* PANDEMONIUM ENGINE */
/* https://github.com/Relintai/pandemonium_engine */
/*************************************************************************/
/* Copyright (c) 2022-present Péter Magyar. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "core/containers/vector.h"
#include "core/typedefs.h"
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.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.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(pos);
}
int find(const T &p_val) const {
return _find_exact(p_val);
}
_FORCE_INLINE_ bool empty() const { return _data.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];
}
};
#endif // VSET_H