mirror of
https://github.com/Redot-Engine/redot-engine.git
synced 2025-12-06 07:17:42 -05:00
Merge commit godotengine/godot@428a762e98
This commit is contained in:
@@ -68,14 +68,13 @@ template <typename TKey, typename TValue,
|
||||
typename Hasher = HashMapHasherDefault,
|
||||
typename Comparator = HashMapComparatorDefault<TKey>,
|
||||
typename Allocator = DefaultTypedAllocator<HashMapElement<TKey, TValue>>>
|
||||
class HashMap {
|
||||
class HashMap : private Allocator {
|
||||
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:
|
||||
Allocator element_alloc;
|
||||
HashMapElement<TKey, TValue> **elements = nullptr;
|
||||
uint32_t *hashes = nullptr;
|
||||
HashMapElement<TKey, TValue> *head_element = nullptr;
|
||||
@@ -84,7 +83,7 @@ private:
|
||||
uint32_t capacity_index = 0;
|
||||
uint32_t num_elements = 0;
|
||||
|
||||
_FORCE_INLINE_ uint32_t _hash(const TKey &p_key) const {
|
||||
_FORCE_INLINE_ static uint32_t _hash(const TKey &p_key) {
|
||||
uint32_t hash = Hasher::hash(p_key);
|
||||
|
||||
if (unlikely(hash == EMPTY_HASH)) {
|
||||
@@ -100,14 +99,14 @@ private:
|
||||
}
|
||||
|
||||
bool _lookup_pos(const TKey &p_key, uint32_t &r_pos) const {
|
||||
if (elements == nullptr || num_elements == 0) {
|
||||
return false; // Failed lookups, no elements
|
||||
}
|
||||
return elements != nullptr && num_elements > 0 && _lookup_pos_unchecked(p_key, _hash(p_key), r_pos);
|
||||
}
|
||||
|
||||
/// Note: Assumes that elements != nullptr
|
||||
bool _lookup_pos_unchecked(const TKey &p_key, uint32_t p_hash, uint32_t &r_pos) const {
|
||||
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 pos = fastmod(p_hash, capacity_inv, capacity);
|
||||
uint32_t distance = 0;
|
||||
|
||||
while (true) {
|
||||
@@ -119,7 +118,7 @@ private:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hashes[pos] == hash && Comparator::compare(elements[pos]->data.key, p_key)) {
|
||||
if (hashes[pos] == p_hash && Comparator::compare(elements[pos]->data.key, p_key)) {
|
||||
r_pos = pos;
|
||||
return true;
|
||||
}
|
||||
@@ -129,7 +128,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void _insert_with_hash(uint32_t p_hash, HashMapElement<TKey, TValue> *p_value) {
|
||||
void _insert_element(uint32_t p_hash, HashMapElement<TKey, TValue> *p_value) {
|
||||
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;
|
||||
@@ -190,14 +189,14 @@ private:
|
||||
continue;
|
||||
}
|
||||
|
||||
_insert_with_hash(old_hashes[i], old_elements[i]);
|
||||
_insert_element(old_hashes[i], old_elements[i]);
|
||||
}
|
||||
|
||||
Memory::free_static(old_elements);
|
||||
Memory::free_static(old_hashes);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ HashMapElement<TKey, TValue> *_insert(const TKey &p_key, const TValue &p_value, bool p_front_insert = false) {
|
||||
_FORCE_INLINE_ HashMapElement<TKey, TValue> *_insert(const TKey &p_key, const TValue &p_value, uint32_t p_hash, bool p_front_insert = false) {
|
||||
uint32_t capacity = hash_table_size_primes[capacity_index];
|
||||
if (unlikely(elements == nullptr)) {
|
||||
// Allocate on demand to save memory.
|
||||
@@ -211,37 +210,28 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
|
||||
if (exists) {
|
||||
elements[pos]->data.value = p_value;
|
||||
return elements[pos];
|
||||
} else {
|
||||
if (num_elements + 1 > MAX_OCCUPANCY * capacity) {
|
||||
ERR_FAIL_COND_V_MSG(capacity_index + 1 == HASH_TABLE_SIZE_MAX, nullptr, "Hash table maximum capacity reached, aborting insertion.");
|
||||
_resize_and_rehash(capacity_index + 1);
|
||||
}
|
||||
|
||||
HashMapElement<TKey, TValue> *elem = element_alloc.new_allocation(HashMapElement<TKey, TValue>(p_key, p_value));
|
||||
|
||||
if (tail_element == nullptr) {
|
||||
head_element = elem;
|
||||
tail_element = elem;
|
||||
} else if (p_front_insert) {
|
||||
head_element->prev = elem;
|
||||
elem->next = head_element;
|
||||
head_element = elem;
|
||||
} else {
|
||||
tail_element->next = elem;
|
||||
elem->prev = tail_element;
|
||||
tail_element = elem;
|
||||
}
|
||||
|
||||
uint32_t hash = _hash(p_key);
|
||||
_insert_with_hash(hash, elem);
|
||||
return elem;
|
||||
if (num_elements + 1 > MAX_OCCUPANCY * capacity) {
|
||||
ERR_FAIL_COND_V_MSG(capacity_index + 1 == HASH_TABLE_SIZE_MAX, nullptr, "Hash table maximum capacity reached, aborting insertion.");
|
||||
_resize_and_rehash(capacity_index + 1);
|
||||
}
|
||||
|
||||
HashMapElement<TKey, TValue> *elem = Allocator::new_allocation(HashMapElement<TKey, TValue>(p_key, p_value));
|
||||
|
||||
if (tail_element == nullptr) {
|
||||
head_element = elem;
|
||||
tail_element = elem;
|
||||
} else if (p_front_insert) {
|
||||
head_element->prev = elem;
|
||||
elem->next = head_element;
|
||||
head_element = elem;
|
||||
} else {
|
||||
tail_element->next = elem;
|
||||
elem->prev = tail_element;
|
||||
tail_element = elem;
|
||||
}
|
||||
|
||||
_insert_element(p_hash, elem);
|
||||
return elem;
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -265,7 +255,7 @@ public:
|
||||
}
|
||||
|
||||
hashes[i] = EMPTY_HASH;
|
||||
element_alloc.delete_allocation(elements[i]);
|
||||
Allocator::delete_allocation(elements[i]);
|
||||
elements[i] = nullptr;
|
||||
}
|
||||
|
||||
@@ -390,7 +380,7 @@ public:
|
||||
elements[pos]->next->prev = elements[pos]->prev;
|
||||
}
|
||||
|
||||
element_alloc.delete_allocation(elements[pos]);
|
||||
Allocator::delete_allocation(elements[pos]);
|
||||
elements[pos] = nullptr;
|
||||
|
||||
num_elements--;
|
||||
@@ -400,11 +390,13 @@ public:
|
||||
// Replace the key of an entry in-place, without invalidating iterators or changing the entries position during iteration.
|
||||
// p_old_key must exist in the map and p_new_key must not, unless it is equal to p_old_key.
|
||||
bool replace_key(const TKey &p_old_key, const TKey &p_new_key) {
|
||||
ERR_FAIL_COND_V(elements == nullptr || num_elements == 0, false);
|
||||
if (p_old_key == p_new_key) {
|
||||
return true;
|
||||
}
|
||||
const uint32_t new_hash = _hash(p_new_key);
|
||||
uint32_t pos = 0;
|
||||
ERR_FAIL_COND_V(_lookup_pos(p_new_key, pos), false);
|
||||
ERR_FAIL_COND_V(_lookup_pos_unchecked(p_new_key, new_hash, pos), false);
|
||||
ERR_FAIL_COND_V(!_lookup_pos(p_old_key, pos), false);
|
||||
HashMapElement<TKey, TValue> *element = elements[pos];
|
||||
|
||||
@@ -420,13 +412,12 @@ public:
|
||||
}
|
||||
hashes[pos] = EMPTY_HASH;
|
||||
elements[pos] = nullptr;
|
||||
// _insert_with_hash will increment this again.
|
||||
// _insert_element will increment this again.
|
||||
num_elements--;
|
||||
|
||||
// Update the HashMapElement with the new key and reinsert it.
|
||||
const_cast<TKey &>(element->data.key) = p_new_key;
|
||||
uint32_t hash = _hash(p_new_key);
|
||||
_insert_with_hash(hash, element);
|
||||
_insert_element(new_hash, element);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -585,10 +576,11 @@ public:
|
||||
}
|
||||
|
||||
TValue &operator[](const TKey &p_key) {
|
||||
const uint32_t hash = _hash(p_key);
|
||||
uint32_t pos = 0;
|
||||
bool exists = _lookup_pos(p_key, pos);
|
||||
bool exists = elements && num_elements > 0 && _lookup_pos_unchecked(p_key, hash, pos);
|
||||
if (!exists) {
|
||||
return _insert(p_key, TValue())->data.value;
|
||||
return _insert(p_key, TValue(), hash)->data.value;
|
||||
} else {
|
||||
return elements[pos]->data.value;
|
||||
}
|
||||
@@ -597,7 +589,15 @@ public:
|
||||
/* Insert */
|
||||
|
||||
Iterator insert(const TKey &p_key, const TValue &p_value, bool p_front_insert = false) {
|
||||
return Iterator(_insert(p_key, p_value, p_front_insert));
|
||||
const uint32_t hash = _hash(p_key);
|
||||
uint32_t pos = 0;
|
||||
bool exists = elements && num_elements > 0 && _lookup_pos_unchecked(p_key, hash, pos);
|
||||
if (!exists) {
|
||||
return Iterator(_insert(p_key, p_value, hash, p_front_insert));
|
||||
} else {
|
||||
elements[pos]->data.value = p_value;
|
||||
return Iterator(elements[pos]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Constructors */
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* search_array.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* REDOT ENGINE */
|
||||
/* https://redotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2024-present Redot Engine contributors */
|
||||
/* (see REDOT_AUTHORS.md) */
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/typedefs.h"
|
||||
|
||||
template <typename T, typename Comparator = Comparator<T>>
|
||||
class SearchArray {
|
||||
public:
|
||||
Comparator compare;
|
||||
|
||||
inline int64_t bisect(const T *p_array, int64_t p_len, const T &p_value, bool p_before) const {
|
||||
int64_t lo = 0;
|
||||
int64_t hi = p_len;
|
||||
if (p_before) {
|
||||
while (lo < hi) {
|
||||
const int64_t mid = (lo + hi) / 2;
|
||||
if (compare(p_array[mid], p_value)) {
|
||||
lo = mid + 1;
|
||||
} else {
|
||||
hi = mid;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (lo < hi) {
|
||||
const int64_t mid = (lo + hi) / 2;
|
||||
if (compare(p_value, p_array[mid])) {
|
||||
hi = mid;
|
||||
} else {
|
||||
lo = mid + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return lo;
|
||||
}
|
||||
};
|
||||
@@ -88,6 +88,10 @@ public:
|
||||
constexpr int64_t rfind(const T &p_val, uint64_t p_from) const;
|
||||
_FORCE_INLINE_ constexpr int64_t rfind(const T &p_val) const { return rfind(p_val, size() - 1); }
|
||||
constexpr uint64_t count(const T &p_val) const;
|
||||
/// Find the index of the given value using binary search.
|
||||
/// Note: Assumes that elements in the span are sorted. Otherwise, use find() instead.
|
||||
template <typename Comparator = Comparator<T>>
|
||||
constexpr uint64_t bisect(const T &p_value, bool p_before, Comparator compare = Comparator()) const;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@@ -121,6 +125,33 @@ constexpr uint64_t Span<T>::count(const T &p_val) const {
|
||||
return amount;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename Comparator>
|
||||
constexpr uint64_t Span<T>::bisect(const T &p_value, bool p_before, Comparator compare) const {
|
||||
uint64_t lo = 0;
|
||||
uint64_t hi = size();
|
||||
if (p_before) {
|
||||
while (lo < hi) {
|
||||
const uint64_t mid = (lo + hi) / 2;
|
||||
if (compare(ptr()[mid], p_value)) {
|
||||
lo = mid + 1;
|
||||
} else {
|
||||
hi = mid;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (lo < hi) {
|
||||
const uint64_t mid = (lo + hi) / 2;
|
||||
if (compare(p_value, ptr()[mid])) {
|
||||
hi = mid;
|
||||
} else {
|
||||
lo = mid + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return lo;
|
||||
}
|
||||
|
||||
// Zero-constructing Span initializes _ptr and _len to 0 (and thus empty).
|
||||
template <typename T>
|
||||
struct is_zero_constructible<Span<T>> : std::true_type {};
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
|
||||
#include "core/error/error_macros.h"
|
||||
#include "core/templates/cowdata.h"
|
||||
#include "core/templates/search_array.h"
|
||||
#include "core/templates/sort_array.h"
|
||||
|
||||
#include <initializer_list>
|
||||
@@ -154,8 +153,7 @@ public:
|
||||
|
||||
template <typename Comparator, typename Value, typename... Args>
|
||||
Size bsearch_custom(const Value &p_value, bool p_before, Args &&...args) {
|
||||
SearchArray<T, Comparator> search{ args... };
|
||||
return search.bisect(ptrw(), size(), p_value, p_before);
|
||||
return span().bisect(p_value, p_before, Comparator{ args... });
|
||||
}
|
||||
|
||||
Vector<T> duplicate() {
|
||||
@@ -317,8 +315,8 @@ public:
|
||||
|
||||
template <typename T>
|
||||
void Vector<T>::reverse() {
|
||||
T *p = ptrw();
|
||||
for (Size i = 0; i < size() / 2; i++) {
|
||||
T *p = ptrw();
|
||||
SWAP(p[i], p[size() - i - 1]);
|
||||
}
|
||||
}
|
||||
@@ -331,8 +329,9 @@ void Vector<T>::append_array(Vector<T> p_other) {
|
||||
}
|
||||
const Size bs = size();
|
||||
resize(bs + ds);
|
||||
T *p = ptrw();
|
||||
for (Size i = 0; i < ds; ++i) {
|
||||
ptrw()[bs + i] = p_other[i];
|
||||
p[bs + i] = p_other[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,203 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/* vmap.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* REDOT ENGINE */
|
||||
/* https://redotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2024-present Redot Engine contributors */
|
||||
/* (see REDOT_AUTHORS.md) */
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/templates/cowdata.h"
|
||||
#include "core/typedefs.h"
|
||||
|
||||
template <typename T, typename V>
|
||||
class VMap {
|
||||
public:
|
||||
struct Pair {
|
||||
T key;
|
||||
V value;
|
||||
|
||||
_FORCE_INLINE_ Pair() {}
|
||||
|
||||
_FORCE_INLINE_ Pair(const T &p_key, const V &p_value) {
|
||||
key = p_key;
|
||||
value = p_value;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
CowData<Pair> _cowdata;
|
||||
|
||||
_FORCE_INLINE_ int _find(const T &p_val, bool &r_exact) const {
|
||||
r_exact = false;
|
||||
if (_cowdata.is_empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int low = 0;
|
||||
int high = _cowdata.size() - 1;
|
||||
const Pair *a = _cowdata.ptr();
|
||||
int middle = 0;
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (low > high) {
|
||||
ERR_PRINT("low > high, this may be a bug");
|
||||
}
|
||||
#endif
|
||||
while (low <= high) {
|
||||
middle = (low + high) / 2;
|
||||
|
||||
if (p_val < a[middle].key) {
|
||||
high = middle - 1; //search low end of array
|
||||
} else if (a[middle].key < p_val) {
|
||||
low = middle + 1; //search high end of array
|
||||
} else {
|
||||
r_exact = true;
|
||||
return middle;
|
||||
}
|
||||
}
|
||||
|
||||
//return the position where this would be inserted
|
||||
if (a[middle].key < p_val) {
|
||||
middle++;
|
||||
}
|
||||
return middle;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int _find_exact(const T &p_val) const {
|
||||
if (_cowdata.is_empty()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int low = 0;
|
||||
int high = _cowdata.size() - 1;
|
||||
int middle;
|
||||
const Pair *a = _cowdata.ptr();
|
||||
|
||||
while (low <= high) {
|
||||
middle = (low + high) / 2;
|
||||
|
||||
if (p_val < a[middle].key) {
|
||||
high = middle - 1; //search low end of array
|
||||
} else if (a[middle].key < p_val) {
|
||||
low = middle + 1; //search high end of array
|
||||
} else {
|
||||
return middle;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public:
|
||||
int insert(const T &p_key, const V &p_val) {
|
||||
bool exact;
|
||||
int pos = _find(p_key, exact);
|
||||
if (exact) {
|
||||
_cowdata.get_m(pos).value = p_val;
|
||||
return pos;
|
||||
}
|
||||
_cowdata.insert(pos, Pair(p_key, p_val));
|
||||
return pos;
|
||||
}
|
||||
|
||||
bool has(const T &p_val) const {
|
||||
return _find_exact(p_val) != -1;
|
||||
}
|
||||
|
||||
void erase(const T &p_val) {
|
||||
int pos = _find_exact(p_val);
|
||||
if (pos < 0) {
|
||||
return;
|
||||
}
|
||||
_cowdata.remove_at(pos);
|
||||
}
|
||||
|
||||
int find(const T &p_val) const {
|
||||
return _find_exact(p_val);
|
||||
}
|
||||
|
||||
int find_nearest(const T &p_val) const {
|
||||
if (_cowdata.is_empty()) {
|
||||
return -1;
|
||||
}
|
||||
bool exact;
|
||||
return _find(p_val, exact);
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int size() const { return _cowdata.size(); }
|
||||
_FORCE_INLINE_ bool is_empty() const { return _cowdata.is_empty(); }
|
||||
|
||||
const Pair *get_array() const {
|
||||
return _cowdata.ptr();
|
||||
}
|
||||
|
||||
Pair *get_array() {
|
||||
return _cowdata.ptrw();
|
||||
}
|
||||
|
||||
const V &getv(int p_index) const {
|
||||
return _cowdata.get(p_index).value;
|
||||
}
|
||||
|
||||
V &getv(int p_index) {
|
||||
return _cowdata.get_m(p_index).value;
|
||||
}
|
||||
|
||||
const T &getk(int p_index) const {
|
||||
return _cowdata.get(p_index).key;
|
||||
}
|
||||
|
||||
T &getk(int p_index) {
|
||||
return _cowdata.get_m(p_index).key;
|
||||
}
|
||||
|
||||
inline const V &operator[](const T &p_key) const {
|
||||
int pos = _find_exact(p_key);
|
||||
|
||||
CRASH_COND(pos < 0);
|
||||
|
||||
return _cowdata.get(pos).value;
|
||||
}
|
||||
|
||||
inline V &operator[](const T &p_key) {
|
||||
int pos = _find_exact(p_key);
|
||||
if (pos < 0) {
|
||||
pos = insert(p_key, V());
|
||||
}
|
||||
|
||||
return _cowdata.get_m(pos).value;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ VMap() {}
|
||||
_FORCE_INLINE_ VMap(std::initializer_list<T> p_init) :
|
||||
_cowdata(p_init) {}
|
||||
_FORCE_INLINE_ VMap(const VMap &p_from) = default;
|
||||
|
||||
void operator=(const VMap &p_from) { _cowdata = p_from._cowdata; }
|
||||
};
|
||||
@@ -39,41 +39,19 @@ template <typename T>
|
||||
class VSet {
|
||||
Vector<T> _data;
|
||||
|
||||
protected:
|
||||
_FORCE_INLINE_ int _find(const T &p_val, bool &r_exact) const {
|
||||
r_exact = false;
|
||||
if (_data.is_empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int low = 0;
|
||||
int high = _data.size() - 1;
|
||||
const T *a = &_data[0];
|
||||
int middle = 0;
|
||||
int64_t pos = _data.span().bisect(p_val, true);
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (low > high) {
|
||||
ERR_PRINT("low > high, this may be a bug");
|
||||
if (pos < _data.size() && !(p_val < _data[pos]) && !(_data[pos] < p_val)) {
|
||||
r_exact = true;
|
||||
}
|
||||
#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;
|
||||
return pos;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ int _find_exact(const T &p_val) const {
|
||||
@@ -81,23 +59,11 @@ class VSet {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int low = 0;
|
||||
int high = _data.size() - 1;
|
||||
int middle;
|
||||
const T *a = &_data[0];
|
||||
int64_t pos = _data.span().bisect(p_val, true);
|
||||
|
||||
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;
|
||||
}
|
||||
if (pos < _data.size() && !(p_val < _data[pos]) && !(_data[pos] < p_val)) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user