This commit is contained in:
Raul Santos 2021-11-09 15:42:28 +01:00 committed by GitHub
commit b637a92529
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 234 additions and 159 deletions

View file

@ -1065,19 +1065,19 @@ void ProjectSettings::_add_builtin_input_map() {
if (InputMap::get_singleton()) {
OrderedHashMap<String, List<Ref<InputEvent>>> builtins = InputMap::get_singleton()->get_builtins();
for (OrderedHashMap<String, List<Ref<InputEvent>>>::Element E = builtins.front(); E; E = E.next()) {
for (const KeyValue<String, List<Ref<InputEvent>>> &E : builtins) {
Array events;
// Convert list of input events into array
for (List<Ref<InputEvent>>::Element *I = E.get().front(); I; I = I->next()) {
events.push_back(I->get());
for (const Ref<InputEvent> &I : E.value) {
events.push_back(I);
}
Dictionary action;
action["deadzone"] = Variant(0.5f);
action["events"] = events;
String action_name = "input/" + E.key();
String action_name = "input/" + E.key;
GLOBAL_DEF(action_name, action);
input_presets.push_back(action_name);
}

View file

@ -37,6 +37,7 @@
#include "core/string/ustring.h"
#include "core/templates/hashfuncs.h"
#include "core/templates/list.h"
#include "core/templates/pair.h"
/**
* @class HashMap
@ -45,61 +46,61 @@
* Implementation of a standard Hashing HashMap, for quick lookups of Data associated with a Key.
* The implementation provides hashers for the default types, if you need a special kind of hasher, provide
* your own.
* @param TKey Key, search is based on it, needs to be hasheable. It is unique in this container.
* @param TData Data, data associated with the key
* @param Hasher Hasher object, needs to provide a valid static hash function for TKey
* @param Comparator comparator object, needs to be able to safely compare two TKey values. It needs to ensure that x == x for any items inserted in the map. Bear in mind that nan != nan when implementing an equality check.
* @param K Key, search is based on it, needs to be hasheable. It is unique in this container.
* @param V Value, data associated with the key
* @param Hasher Hasher object, needs to provide a valid static hash function for K
* @param Comparator comparator object, needs to be able to safely compare two K values. It needs to ensure that x == x for any items inserted in the map. Bear in mind that nan != nan when implementing an equality check.
* @param MIN_HASH_TABLE_POWER Miminum size of the hash table, as a power of two. You rarely need to change this parameter.
* @param RELATIONSHIP Relationship at which the hash table is resized. if amount of elements is RELATIONSHIP
* times bigger than the hash table, table is resized to solve this condition. if RELATIONSHIP is zero, table is always MIN_HASH_TABLE_POWER.
*
*/
template <class TKey, class TData, class Hasher = HashMapHasherDefault, class Comparator = HashMapComparatorDefault<TKey>, uint8_t MIN_HASH_TABLE_POWER = 3, uint8_t RELATIONSHIP = 8>
template <class K, class V, class Hasher = HashMapHasherDefault, class Comparator = HashMapComparatorDefault<K>, uint8_t MIN_HASH_TABLE_POWER = 3, uint8_t RELATIONSHIP = 8>
class HashMap {
public:
struct Pair {
TKey key;
TData data;
Pair(const TKey &p_key) :
key(p_key),
data() {}
Pair(const TKey &p_key, const TData &p_data) :
key(p_key),
data(p_data) {
}
};
struct Element {
private:
friend class HashMap;
uint32_t hash = 0;
Element *next = nullptr;
Element() {}
Pair pair;
Element *_next = nullptr;
KeyValue<K, V> _data;
public:
const TKey &key() const {
return pair.key;
}
KeyValue<K, V> &key_value() { return _data; }
const KeyValue<K, V> &key_value() const { return _data; }
TData &value() {
return pair.data;
const Element *next() const {
return _next;
}
const TData &value() const {
return pair.value();
Element *next() {
return _next;
}
Element(const TKey &p_key) :
pair(p_key) {}
const K &key() const {
return _data.key;
}
V &value() {
return _data.value;
}
const V &value() const {
return _data.value;
}
V &get() {
return _data.value;
}
const V &get() const {
return _data.value;
}
Element(const KeyValue<K, V> &p_data) :
_data(p_data) {}
Element(const Element &p_other) :
hash(p_other.hash),
pair(p_other.pair.key, p_other.pair.data) {}
_data(p_other._data) {}
};
typedef KeyValue<K, V> ValueType;
private:
Element **hash_table = nullptr;
uint8_t hash_table_power = 0;
@ -165,9 +166,9 @@ private:
for (int i = 0; i < (1 << hash_table_power); i++) {
while (hash_table[i]) {
Element *se = hash_table[i];
hash_table[i] = se->next;
hash_table[i] = se->_next;
int new_pos = se->hash & ((1 << new_hash_table_power) - 1);
se->next = new_hash_table[new_pos];
se->_next = new_hash_table[new_pos];
new_hash_table[new_pos] = se;
}
}
@ -179,7 +180,7 @@ private:
}
/* I want to have only one function.. */
_FORCE_INLINE_ const Element *get_element(const TKey &p_key) const {
_FORCE_INLINE_ const Element *get_element(const K &p_key) const {
uint32_t hash = Hasher::hash(p_key);
uint32_t index = hash & ((1 << hash_table_power) - 1);
@ -187,24 +188,24 @@ private:
while (e) {
/* checking hash first avoids comparing key, which may take longer */
if (e->hash == hash && Comparator::compare(e->pair.key, p_key)) {
/* the pair exists in this hashtable, so just update data */
if (e->hash == hash && Comparator::compare(e->_data.key, p_key)) {
/* the KeyValue exists in this hashtable, so just update data */
return e;
}
e = e->next;
e = e->_next;
}
return nullptr;
}
Element *create_element(const TKey &p_key) {
Element *create_element(const K &p_key) {
/* if element doesn't exist, create it */
Element *e = memnew(Element(p_key));
Element *e = memnew(Element(KeyValue<K, V>(p_key, V())));
ERR_FAIL_COND_V_MSG(!e, nullptr, "Out of memory.");
uint32_t hash = Hasher::hash(p_key);
uint32_t index = hash & ((1 << hash_table_power) - 1);
e->next = hash_table[index];
e->_next = hash_table[index];
e->hash = hash;
hash_table[index] = e;
@ -234,45 +235,45 @@ private:
const Element *e = p_t.hash_table[i];
while (e) {
Element *le = memnew(Element(*e)); /* local element */
Element *le = memnew(Element(KeyValue(e->_data.key, e->_data.value))); /* local element */
/* add to list and reassign pointers */
le->next = hash_table[i];
le->_next = hash_table[i];
hash_table[i] = le;
e = e->next;
e = e->_next;
}
}
}
public:
Element *set(const TKey &p_key, const TData &p_data) {
return set(Pair(p_key, p_data));
Element *set(const K &p_key, const V &p_data) {
return set(KeyValue(p_key, p_data));
}
Element *set(const Pair &p_pair) {
Element *set(const KeyValue<K, V> &p_key_value) {
Element *e = nullptr;
if (!hash_table) {
make_hash_table(); // if no table, make one
} else {
e = const_cast<Element *>(get_element(p_pair.key));
e = const_cast<Element *>(get_element(p_key_value.key));
}
/* if we made it up to here, the pair doesn't exist, create and assign */
/* if we made it up to here, the KeyValue doesn't exist, create and assign */
if (!e) {
e = create_element(p_pair.key);
e = create_element(p_key_value.key);
if (!e) {
return nullptr;
}
check_hash_table(); // perform mantenience routine
}
e->pair.data = p_pair.data;
e->_data.value = p_key_value.value;
return e;
}
bool has(const TKey &p_key) const {
bool has(const K &p_key) const {
return getptr(p_key) != nullptr;
}
@ -282,14 +283,14 @@ public:
* first with has(key)
*/
const TData &get(const TKey &p_key) const {
const TData *res = getptr(p_key);
const V &get(const K &p_key) const {
const V *res = getptr(p_key);
CRASH_COND_MSG(!res, "Map key not found.");
return *res;
}
TData &get(const TKey &p_key) {
TData *res = getptr(p_key);
V &get(const K &p_key) {
V *res = getptr(p_key);
CRASH_COND_MSG(!res, "Map key not found.");
return *res;
}
@ -299,7 +300,7 @@ public:
* This is mainly used for speed purposes.
*/
_FORCE_INLINE_ TData *getptr(const TKey &p_key) {
_FORCE_INLINE_ V *getptr(const K &p_key) {
if (unlikely(!hash_table)) {
return nullptr;
}
@ -307,13 +308,13 @@ public:
Element *e = const_cast<Element *>(get_element(p_key));
if (e) {
return &e->pair.data;
return &e->_data.value;
}
return nullptr;
}
_FORCE_INLINE_ const TData *getptr(const TKey &p_key) const {
_FORCE_INLINE_ const V *getptr(const K &p_key) const {
if (unlikely(!hash_table)) {
return nullptr;
}
@ -321,7 +322,7 @@ public:
const Element *e = const_cast<Element *>(get_element(p_key));
if (e) {
return &e->pair.data;
return &e->_data.value;
}
return nullptr;
@ -333,7 +334,7 @@ public:
*/
template <class C>
_FORCE_INLINE_ TData *custom_getptr(C p_custom_key, uint32_t p_custom_hash) {
_FORCE_INLINE_ V *custom_getptr(C p_custom_key, uint32_t p_custom_hash) {
if (unlikely(!hash_table)) {
return nullptr;
}
@ -345,19 +346,19 @@ public:
while (e) {
/* checking hash first avoids comparing key, which may take longer */
if (e->hash == hash && Comparator::compare(e->pair.key, p_custom_key)) {
/* the pair exists in this hashtable, so just update data */
return &e->pair.data;
if (e->hash == hash && Comparator::compare(e->_data.key, p_custom_key)) {
/* the KeyValue exists in this hashtable, so just update data */
return &e->_data.value;
}
e = e->next;
e = e->_next;
}
return nullptr;
}
template <class C>
_FORCE_INLINE_ const TData *custom_getptr(C p_custom_key, uint32_t p_custom_hash) const {
_FORCE_INLINE_ const V *custom_getptr(C p_custom_key, uint32_t p_custom_hash) const {
if (unlikely(!hash_table)) {
return nullptr;
}
@ -369,12 +370,12 @@ public:
while (e) {
/* checking hash first avoids comparing key, which may take longer */
if (e->hash == hash && Comparator::compare(e->pair.key, p_custom_key)) {
/* the pair exists in this hashtable, so just update data */
return &e->pair.data;
if (e->hash == hash && Comparator::compare(e->_data.key, p_custom_key)) {
/* the KeyValue exists in this hashtable, so just update data */
return &e->_data.value;
}
e = e->next;
e = e->_next;
}
return nullptr;
@ -384,7 +385,7 @@ public:
* Erase an item, return true if erasing was successful
*/
bool erase(const TKey &p_key) {
bool erase(const K &p_key) {
if (unlikely(!hash_table)) {
return false;
}
@ -396,12 +397,12 @@ public:
Element *p = nullptr;
while (e) {
/* checking hash first avoids comparing key, which may take longer */
if (e->hash == hash && Comparator::compare(e->pair.key, p_key)) {
if (e->hash == hash && Comparator::compare(e->_data.key, p_key)) {
if (p) {
p->next = e->next;
p->_next = e->_next;
} else {
//begin of list
hash_table[index] = e->next;
hash_table[index] = e->_next;
}
memdelete(e);
@ -416,17 +417,17 @@ public:
}
p = e;
e = e->next;
e = e->_next;
}
return false;
}
inline const TData &operator[](const TKey &p_key) const { //constref
inline const V &operator[](const K &p_key) const { //constref
return get(p_key);
}
inline TData &operator[](const TKey &p_key) { //assignment
inline V &operator[](const K &p_key) { //assignment
Element *e = nullptr;
if (!hash_table) {
@ -435,14 +436,14 @@ public:
e = const_cast<Element *>(get_element(p_key));
}
/* if we made it up to here, the pair doesn't exist, create */
/* if we made it up to here, the KeyValue doesn't exist, create */
if (!e) {
e = create_element(p_key);
CRASH_COND(!e);
check_hash_table(); // perform mantenience routine
}
return e->pair.data;
return e->_data.value;
}
/**
@ -452,7 +453,7 @@ public:
*
* Example:
*
* const TKey *k=nullptr;
* const K *k=nullptr;
*
* while( (k=table.next(k)) ) {
*
@ -460,7 +461,7 @@ public:
* }
*
*/
const TKey *next(const TKey *p_key) const {
const K *next(const K *p_key) const {
if (unlikely(!hash_table)) {
return nullptr;
}
@ -469,7 +470,7 @@ public:
for (int i = 0; i < (1 << hash_table_power); i++) {
if (hash_table[i]) {
return &hash_table[i]->pair.key;
return &hash_table[i]->_data.key;
}
}
@ -477,16 +478,16 @@ public:
const Element *e = get_element(*p_key);
ERR_FAIL_COND_V_MSG(!e, nullptr, "Invalid key supplied.");
if (e->next) {
if (e->_next) {
/* if there is a "next" in the list, return that */
return &e->next->pair.key;
return &e->_next->_data.key;
} else {
/* go to next elements */
uint32_t index = e->hash & ((1 << hash_table_power) - 1);
index++;
for (int i = index; i < (1 << hash_table_power); i++) {
if (hash_table[i]) {
return &hash_table[i]->pair.key;
return &hash_table[i]->_data.key;
}
}
}
@ -511,7 +512,7 @@ public:
for (int i = 0; i < (1 << hash_table_power); i++) {
while (hash_table[i]) {
Element *e = hash_table[i];
hash_table[i] = e->next;
hash_table[i] = e->_next;
memdelete(e);
}
}
@ -528,15 +529,15 @@ public:
copy_from(p_table);
}
void get_key_list(List<TKey> *r_keys) const {
void get_key_list(List<K> *r_keys) const {
if (unlikely(!hash_table)) {
return;
}
for (int i = 0; i < (1 << hash_table_power); i++) {
Element *e = hash_table[i];
while (e) {
r_keys->push_back(e->pair.key);
e = e->next;
r_keys->push_back(e->_data.key);
e = e->_next;
}
}
}

View file

@ -132,7 +132,8 @@ public:
data->erase(this);
}
_FORCE_INLINE_ Element() {}
_FORCE_INLINE_ Element(T p_value) :
value(p_value) {}
};
typedef T ValueType;
@ -279,7 +280,7 @@ public:
/**
* store a new element at the end of the list
*/
Element *push_back(const T &value) {
Element *push_back(const T &p_value) {
if (!_data) {
_data = memnew_allocator(_Data, A);
_data->first = nullptr;
@ -287,9 +288,7 @@ public:
_data->size_cache = 0;
}
Element *n = memnew_allocator(Element, A);
n->value = (T &)value;
Element *n = memnew_allocator(Element((T &)p_value), A);
n->prev_ptr = _data->last;
n->next_ptr = nullptr;
n->data = _data;
@ -318,7 +317,7 @@ public:
/**
* store a new element at the beginning of the list
*/
Element *push_front(const T &value) {
Element *push_front(const T &p_value) {
if (!_data) {
_data = memnew_allocator(_Data, A);
_data->first = nullptr;
@ -326,8 +325,7 @@ public:
_data->size_cache = 0;
}
Element *n = memnew_allocator(Element, A);
n->value = (T &)value;
Element *n = memnew_allocator(Element((T &)p_value), A);
n->prev_ptr = nullptr;
n->next_ptr = _data->first;
n->data = _data;
@ -360,8 +358,7 @@ public:
return push_back(p_value);
}
Element *n = memnew_allocator(Element, A);
n->value = (T &)p_value;
Element *n = memnew_allocator(Element((T &)p_value), A);
n->prev_ptr = p_element;
n->next_ptr = p_element->next_ptr;
n->data = _data;
@ -386,8 +383,7 @@ public:
return push_back(p_value);
}
Element *n = memnew_allocator(Element, A);
n->value = (T &)p_value;
Element *n = memnew_allocator(Element((T &)p_value), A);
n->prev_ptr = p_element->prev_ptr;
n->next_ptr = p_element;
n->data = _data;

View file

@ -45,8 +45,8 @@
*/
template <class K, class V, class Hasher = HashMapHasherDefault, class Comparator = HashMapComparatorDefault<K>, uint8_t MIN_HASH_TABLE_POWER = 3, uint8_t RELATIONSHIP = 8>
class OrderedHashMap {
typedef List<Pair<const K *, V>> InternalList;
typedef HashMap<K, typename InternalList::Element *, Hasher, Comparator, MIN_HASH_TABLE_POWER, RELATIONSHIP> InternalMap;
typedef HashMap<K, V, Hasher, Comparator, MIN_HASH_TABLE_POWER, RELATIONSHIP> InternalMap;
typedef List<typename InternalMap::Element *> InternalList;
InternalList list;
InternalMap map;
@ -56,39 +56,26 @@ public:
friend class OrderedHashMap<K, V, Hasher, Comparator, MIN_HASH_TABLE_POWER, RELATIONSHIP>;
typename InternalList::Element *list_element = nullptr;
typename InternalList::Element *prev_element = nullptr;
typename InternalList::Element *next_element = nullptr;
Element(typename InternalList::Element *p_element) {
list_element = p_element;
if (list_element) {
next_element = list_element->next();
prev_element = list_element->prev();
}
}
Element(typename InternalList::Element *p_element) :
list_element(p_element) {}
public:
_FORCE_INLINE_ Element() {}
Element(const Element &other) :
list_element(other.list_element) {}
Element next() const {
return Element(next_element);
return Element(list_element ? list_element->next() : nullptr);
}
Element prev() const {
return Element(prev_element);
}
Element(const Element &other) :
list_element(other.list_element),
prev_element(other.prev_element),
next_element(other.next_element) {
return Element(list_element ? list_element->prev() : nullptr);
}
Element &operator=(const Element &other) {
list_element = other.list_element;
next_element = other.next_element;
prev_element = other.prev_element;
return *this;
}
@ -103,29 +90,34 @@ public:
return (list_element != nullptr);
}
KeyValue<K, V> &key_value() const {
CRASH_COND(!list_element);
return list_element->get()->key_value();
}
const K &key() const {
CRASH_COND(!list_element);
return *(list_element->get().first);
return list_element->get()->key();
}
V &value() {
CRASH_COND(!list_element);
return list_element->get().second;
return list_element->get()->value();
}
const V &value() const {
CRASH_COND(!list_element);
return list_element->get().second;
return list_element->get()->value();
}
V &get() {
CRASH_COND(!list_element);
return list_element->get().second;
return list_element->get()->value();
}
const V &get() const {
CRASH_COND(!list_element);
return list_element->get().second;
return list_element->get()->value();
}
};
@ -135,8 +127,7 @@ public:
const typename InternalList::Element *list_element = nullptr;
ConstElement(const typename InternalList::Element *p_element) :
list_element(p_element) {
}
list_element(p_element) {}
public:
_FORCE_INLINE_ ConstElement() {}
@ -171,51 +162,138 @@ public:
const K &key() const {
CRASH_COND(!list_element);
return *(list_element->get().first);
return list_element->get()->key();
}
const V &value() const {
CRASH_COND(!list_element);
return list_element->get().second;
return list_element->get()->value();
}
const V &get() const {
CRASH_COND(!list_element);
return list_element->get().second;
return list_element->get()->value();
}
};
typedef KeyValue<K, V> ValueType;
struct Iterator {
_FORCE_INLINE_ KeyValue<K, V> &operator*() const {
return E.key_value();
}
_FORCE_INLINE_ KeyValue<K, V> *operator->() const { return &E.key_value(); }
_FORCE_INLINE_ Iterator &operator++() {
E = E.next();
return *this;
}
_FORCE_INLINE_ Iterator &operator--() {
E = E.prev();
return *this;
}
_FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; }
_FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; }
Iterator(Element p_E) { E = p_E; }
Iterator() {}
Iterator(const Iterator &p_it) { E = p_it.E; }
private:
Element E = Element(nullptr);
};
struct ConstIterator {
_FORCE_INLINE_ const KeyValue<K, V> &operator*() const {
return E.key_value();
}
_FORCE_INLINE_ const KeyValue<K, V> *operator->() const { return &E.key_value(); }
_FORCE_INLINE_ ConstIterator &operator++() {
E = E.next();
return *this;
}
_FORCE_INLINE_ ConstIterator &operator--() {
E = E.prev();
return *this;
}
_FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return E == b.E; }
_FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return E != b.E; }
ConstIterator(const Element p_E) { E = p_E; }
ConstIterator() {}
ConstIterator(const ConstIterator &p_it) { E = p_it.E; }
private:
const Element E = Element(nullptr);
};
_FORCE_INLINE_ Iterator begin() {
return Iterator(front());
}
_FORCE_INLINE_ Iterator end() {
return Iterator(nullptr);
}
#if 0
//to use when replacing find()
_FORCE_INLINE_ Iterator find(const K &p_key) {
return Iterator(find(p_key));
}
#endif
_FORCE_INLINE_ void remove(const Iterator &p_iter) {
return erase(p_iter.E);
}
_FORCE_INLINE_ ConstIterator begin() const {
return ConstIterator(front());
}
_FORCE_INLINE_ ConstIterator end() const {
return ConstIterator(nullptr);
}
#if 0
//to use when replacing find()
_FORCE_INLINE_ ConstIterator find(const K &p_key) const {
return ConstIterator(find(p_key));
}
#endif
ConstElement find(const K &p_key) const {
typename InternalList::Element *const *list_element = map.getptr(p_key);
if (list_element) {
return ConstElement(*list_element);
if (map.has(p_key)) {
const typename InternalList::Element *it = list.front();
while (it) {
if (it->get()->key() == p_key) {
return ConstElement(it);
}
it = it->next();
}
}
return ConstElement(nullptr);
}
Element find(const K &p_key) {
typename InternalList::Element **list_element = map.getptr(p_key);
if (list_element) {
return Element(*list_element);
if (map.has(p_key)) {
typename InternalList::Element *it = list.front();
while (it) {
if (it->get()->key() == p_key) {
return Element(it);
}
it = it->next();
}
}
return Element(nullptr);
}
Element insert(const K &p_key, const V &p_value) {
typename InternalList::Element **list_element = map.getptr(p_key);
if (list_element) {
(*list_element)->get().second = p_value;
return Element(*list_element);
if (!map.has(p_key)) {
typename InternalMap::Element *new_element = map.set(p_key, p_value);
typename InternalList::Element *list_element = list.push_back(new_element);
return Element(list_element);
}
// Incorrectly set the first value of the pair with a value that will
// be invalid as soon as we leave this function...
typename InternalList::Element *new_element = list.push_back(Pair<const K *, V>(&p_key, p_value));
// ...this is needed here in case the hashmap recursively reference itself...
typename InternalMap::Element *e = map.set(p_key, new_element);
// ...now we can set the right value !
new_element->get().first = &e->key();
return Element(new_element);
map.set(p_key, p_value);
return find(p_key);
}
void erase(Element &p_element) {
@ -225,9 +303,9 @@ public:
}
bool erase(const K &p_key) {
typename InternalList::Element **list_element = map.getptr(p_key);
if (list_element) {
list.erase(*list_element);
const Element element = find(p_key);
if (element.list_element) {
list.erase(element.list_element);
map.erase(p_key);
return true;
}