diff --git a/include/fennec/containers/map.h b/include/fennec/containers/map.h index e596653..5fb6205 100644 --- a/include/fennec/containers/map.h +++ b/include/fennec/containers/map.h @@ -54,11 +54,14 @@ struct map { // Definitions ========================================================================================================= public: + struct key_hash; + struct node_equals; using key_t = KeyT; using value_t = ValueT; using elem_t = pair; using alloc_t = typename allocator_traits::template rebind; using hash_t = Hash; + using set_t = set; // We only want to hash the key struct key_hash : hash_t { @@ -93,19 +96,8 @@ public: /// \param key Key value to access /// \returns A pointer to the value associated with `key`, `nullptr` if `key` is not present. constexpr value_t* operator[](const KeyT& key) { - union U { // Hacky way of avoiding constructing the value, TODO: Check for warnings on other compilers - pair root; - pair val; - - ~U() { - fennec::destruct(&root); - } - } trick = { .root = { key, 0 } }; - auto it = _set.find(trick.val); - if (it == _set.end()) { - return nullptr; - } - return &_set.at(it)->second; + auto it = _set.at(this->_find(key)); + return it ? &it->second : nullptr; } /// @@ -113,19 +105,8 @@ public: /// \param key Key value to access /// \returns A const-qualified pointer to the value associated with `key`, `nullptr` if `key` is not present. constexpr const value_t* operator[](const KeyT& key) const { - union U { // Hacky way of avoiding constructing the value, TODO: Check for warnings on other compilers - pair root; - pair val; - - ~U() { - fennec::destruct(&root); - } - } trick = { .root = { key, 0 } }; // Only initialize root - auto it = _set.find(trick.val); - if (it == _set.end()) { - return nullptr; - } - return &_set.at(it)->second; + auto it = _set.at(this->_find(key)); + return it ? &it->second : nullptr; } /// @@ -133,43 +114,21 @@ public: /// \tparam ArgT Argument Type /// \param arg Argument to construct the key with /// \returns A pointer to the value associated with `key`, `nullptr` if `key` is not present. - template - constexpr value_t* operator[](ArgT&& arg) { - union U { // Hacky way of avoiding constructing the value, TODO: Check for warnings on other compilers - pair root; - pair val; - - ~U() { - fennec::destruct(&root); - } - } trick = { .root = { key_t(fennec::forward(arg)), 0 } }; // Only initialize root - auto it = _set.find(trick.val); - if (it == _set.end()) { - return nullptr; - } - return &_set.at(it)->second; + template + constexpr value_t* operator[](ArgsT&&...args) { + auto it = _set.at(this->_find(fennec::forward(args)...)); + return it ? &it->second : nullptr; } /// /// \brief Argument Key Const Access Operator - /// \tparam ArgT Argument Type - /// \param arg Argument to construct the key with + /// \tparam ArgsT Argument Type + /// \param args Argument to construct the key with /// \returns A const-qualified pointer to the value associated with `key`, `nullptr` if `key` is not present. - template - constexpr const value_t* operator[](ArgT&& arg) const { - union U { // Hacky way of avoiding constructing the value, TODO: Check for warnings on other compilers - pair root; - pair val; - - ~U() { - fennec::destruct(&root); - } - } trick = { .root = { key_t(fennec::forward(arg)), 0 } }; // Only initialize root - auto it = _set.find(trick.val); - if (it == _set.end()) { - return nullptr; - } - return &_set.at(it)->second; + template + constexpr const value_t* operator[](ArgsT&&...args) const { + auto it = _set.at(this->_find(fennec::forward(args)...)); + return it ? &it->second : nullptr; } @@ -179,12 +138,15 @@ public: /// \brief Key-Value Insertion /// \param pair a pair containing the key and its value constexpr void insert(elem_t&& pair) { - auto it = _set.find(pair); - if (it == _set.end()) { - _set.at(it)->second = fennec::move(pair.second); - return; - } - _set.insert(fennec::forward(pair)); + this->_insert(fennec::forward(pair)); + } + + /// + /// \brief Key-Value Insertion + /// \param args Arguments for constructing the key-value pair + template + constexpr void emplace(const KeyT& key, ArgsT&&...args) { + this->_insert(key, fennec::forward(args)...); } /// @@ -192,30 +154,21 @@ public: /// \param args Arguments for constructing the key-value pair template constexpr void emplace(ArgsT&&...args) { - _set.insert(elem_t(args...)); + this->_insert(fennec::forward(args)...); } /// /// \brief Erase a key /// \param key key to erase constexpr void erase(KeyT&& key) { - union U { // Hacky way of avoiding constructing the value, TODO: Check for warnings on other compilers - pair root; - pair val; - - ~U() { - fennec::destruct(&root); - } - } trick = { .root = { fennec::forward(key), 0 } }; - _set.erase(trick.val); + _set.erase(this->_find(fennec::forward(key))); } /// /// \brief Erase a key /// \param key key to erase constexpr void erase(const KeyT& key) { - KeyT val = key; - erase(fennec::move(val)); + _set.erase(this->_find(key)); } /// @@ -224,6 +177,15 @@ public: /// \param args Arguments to construct a key to erase template constexpr void erase(ArgsT&&...args) { + _set.erase(this->_find(fennec::forward(args)...)); + } + + +private: + set_t _set; + + template + set_t::iterator _find(ArgsT&&...args) { union U { // Hacky way of avoiding constructing the value, TODO: Check for warnings on other compilers pair root; pair val; @@ -232,12 +194,19 @@ public: fennec::destruct(&root); } } trick = { .root = { KeyT(fennec::forward(args)...), 0 } }; - _set.erase(trick.val); + return _set.find(trick.val); } - -private: - set _set; + template + constexpr void _insert(ArgsT&&...args) { + elem_t elem(fennec::forward(args)...); + auto it = this->_find(elem.first); + if (it != _set.end()) { + _set.at(it)->second = fennec::move(elem.second); + } else { + _set.insert(fennec::move(elem)); + } + } }; } diff --git a/include/fennec/containers/set.h b/include/fennec/containers/set.h index 397fcfa..68d7a6c 100644 --- a/include/fennec/containers/set.h +++ b/include/fennec/containers/set.h @@ -215,6 +215,9 @@ public: /// \param val Value to find /// \returns An iterator at the location of the value constexpr iterator find(const elem_t& val) const { + if (capacity() == 0) { + return end(); + } size_t s = _hash(val) % capacity(); // Initial search index int psl = (_size != 0) ? _sumpsl / _size : 0; // Initial psl size_t i = (s + psl) % capacity(); // Median search @@ -233,15 +236,15 @@ public: size_t i0 = (i + capacity() - n) % capacity(); // Prevent index underflow size_t i1 = (i + n) % capacity(); int p0 = psl - n, p1 = psl + n; - bool c0 = false, c1 = false; + bool c0 = p0 >= 0 && _alloc[i0].psl >= p0, c1 = _alloc[i1].psl >= p1; // Check that we are in range - if ((c0 = (p0 >= 0 && _alloc[i0].psl >= p0)) && _alloc[i0].value) { + if (c0 && _alloc[i0].value) { if (*_alloc[i0].value == val) { return iterator(this, i); } } - if ((c1 = (_alloc[i1].psl >= p1)) && _alloc[i1].value) { + if (c1 && _alloc[i1].value) { if (*_alloc[i1].value == val) { return iterator(this, i); } @@ -269,7 +272,12 @@ public: /// \returns A pointer to the element, `nullptr` if not found. /// The value should not be changed in a manner that will change the hash of the element. constexpr elem_t* at(const iterator& it) { - if (not _alloc[it._i].value) return nullptr; + if (it == end()) { + return nullptr; + } + if (not _alloc[it._i].value) { + return nullptr; + } return &*_alloc[it._i].value; } @@ -288,35 +296,14 @@ public: /// \brief Move Insertion /// \param val Value to insert constexpr void insert(elem_t&& val) { - if (_size == 0 or double(_size) / capacity() >= _load) { // expand when full - _expand(); - } - - elem_t value = fennec::forward(val); - size_t i = _hash(value) % capacity(); // Initial search index - int psl = 0; - while (_alloc[i].value) { // Search for empty cell - if (_equal(*_alloc[i].value, val)) { // Check to see if this element is already inserted - return; - } - if (psl > _alloc[i].psl) { // When psl is higher, swap - _sumpsl += psl - _alloc[i].psl; - fennec::swap(_alloc[i].psl, psl); - fennec::swap(*_alloc[i].value, value); - } - i = (i + 1) % capacity(); ++psl; - } - _alloc[i].value = fennec::move(value); - _sumpsl += (_alloc[i].psl = psl); - ++_size; + this->_insert(fennec::forward(val)); } /// /// \brief Copy Insertion /// \param val Value to insert constexpr void insert(const elem_t& val) { - elem_t value = val; // Copy Constructor invoked here - this->insert(fennec::move(value)); // Only invokes moves + this->_insert(val); } /// @@ -325,8 +312,7 @@ public: /// \param args Arguments to construct with template constexpr void emplace(ArgsT&&...args) { - elem_t value = elem_t(fennec::forward(args)...); // Constructor invoked here - this->insert(fennec::move(value)); // Only invokes moves + this->_insert(fennec::forward(args)...); } /// @@ -398,11 +384,11 @@ public: return &*_set->_alloc[_i].value; } - constexpr bool operator==(const iterator& it) { + constexpr bool operator==(const iterator& it) const { return _set == it._set and _i == it._i; } - constexpr bool operator!=(const iterator& it) { + constexpr bool operator!=(const iterator& it) const { return _set != it._set or _i != it._i; } @@ -450,6 +436,31 @@ private: fennec::swap(_alloc, cpy._alloc); } + template + constexpr void _insert(ArgsT&&...args) { + if (_size == 0 or double(_size) / capacity() >= _load) { // expand when full + _expand(); + } + + elem_t value(fennec::forward(args)...); + size_t i = _hash(value) % capacity(); // Initial search index + int psl = 0; + while (_alloc[i].value) { // Search for empty cell + if (_equal(*_alloc[i].value, value)) { // Check to see if this element is already inserted + return; + } + if (psl > _alloc[i].psl) { // When psl is higher, swap + _sumpsl += psl - _alloc[i].psl; + fennec::swap(_alloc[i].psl, psl); + fennec::swap(*_alloc[i].value, value); + } + i = (i + 1) % capacity(); ++psl; + } + _alloc[i].value = fennec::move(value); + _sumpsl += (_alloc[i].psl = psl); + ++_size; + } + allocation _alloc; hash_t _hash; equal_t _equal; diff --git a/include/fennec/scene/component.h b/include/fennec/scene/component.h index 4a9376b..f33d658 100644 --- a/include/fennec/scene/component.h +++ b/include/fennec/scene/component.h @@ -20,6 +20,8 @@ #define FENNEC_SCENE_COMPONENT_H #include +#include +#include #include #include @@ -28,40 +30,176 @@ namespace fennec class component { public: - using component_create = component (*)(size_t); - using component_find = component* (*)(size_t); - using component_erase = void (*)(size_t); - struct type { - string name; - component_create create; - component_find find; - component_erase erase; +// TYPEDEFS & CONSTANTS ================================================================================================ + using component_create = component (*)(size_t); + using component_find = component* (*)(size_t); + using component_destroy = void (*)(size_t); + using component_tick = void (*)(size_t, double); + using component_frame = void (*)(size_t, uint64_t); + + +// TYPE OPERATIONS ===================================================================================================== + + struct type_info { + string name; + component_create create; + component_find find; + component_destroy destroy; + component_tick tick; + component_frame frame; }; private: - static dynarray& _type_list() { - static dynarray type_list; + // Private Registry + + static auto& _type_list() { + static dynarray> type_list; return type_list; } - static void _register_type(uint64_t id, const cstring& name, component_create create, component_find find, component_erase erase) { - dynarray& type_list = _type_list(); + static void _register_type( uint64_t id, const cstring& name, + component_create create, component_find find, component_destroy destroy, + component_tick tick, component_frame frame) { + auto& type_list = _type_list(); if (id > type_list.size()) { type_list.resize(id + 1); } - type_list[id] = { name, create, find, erase }; + type_list[id] = type_info{ name, create, find, destroy, tick, frame }; + } + + static void _unregister_type(uint64_t id) { + _type_list()[id] = nullopt; + } + + static auto& _default_storage() { + static map> data; + return data; } public: + // Public Registry + + /// + /// \brief Get an uuid for the specified component type + /// \tparam ComponentT The component type + /// \returns An uuid that is associated with the type template - static void register_type(const cstring& name, component_create create, component_find find, component_erase erase) { - component::_register_type(typeuuid(), name, create, find, erase); + static uint64_t uuid() { + return typeuuid(); } - static const dynarray& type_list() { + /// + /// \brief Default storage function for default creation, retrieval, and destruction + template + static constexpr auto& default_storage() { + auto& data = _default_storage(); + return data[uuid()]; + } + + /// + /// \brief Default creation function for a component + /// \tparam ComponentT Type of the component + /// \param node The node to associate the component with + /// \returns The component created by this function + template + static constexpr component* default_create(size_t node) { + auto& storage = default_storage(); + if (not storage[node]) { + storage.emplace(node); + } + return storage[node]; + } + + /// + /// \brief Default retrieval function for a component + /// \tparam ComponentT Type of the component + /// \param node The node the component is associated with + /// \returns The component found by this function + template + static constexpr component* default_find(size_t node) { + auto& storage = default_storage(); + return storage[node]; + } + + /// + /// \brief Default destruction function for a component + /// \tparam ComponentT Type of the component + /// \param node The node the component is associated with + template + static constexpr void default_destroy(size_t node) { + default_storage().erase(node); + } + + /// + /// \brief Register a type with the component system + /// \tparam ComponentT The component type + /// \param name The name of the type + /// \param create The function used to create a component, given a scene node. **MUST NOT BE NULL** + /// \param find The function used to find a component, given a scene node. **MUST NOT BE NULL** + /// \param destroy The function used to destroy a component of a scene node. **MUST NOT BE NULL** + template + static void register_type(const cstring& name, component_tick tick, component_frame frame, + component_create create = default_create, + component_find find = default_find, + component_destroy destroy = default_destroy) { + component::_register_type(uuid(), name, create, find, destroy, tick, frame); + } + + template + static void unregister_type() { + component::_unregister_type(uuid()); + } + + /// + /// \brief Create a component of type `ComponentT` + /// \tparam ComponentT The type to create + /// \param node The node to associate the component with + /// \returns The created component + template + static component* create(size_t node) { + auto& type = _type_list()[uuid()]; + return type ? *type->create(node) : nullptr; + } + + template + static component* find(size_t node) { + auto& type = _type_list()[uuid()]; + return type ? *type->find(node) : nullptr; + } + + template + static void destroy(size_t node) { + auto& type = _type_list()[uuid()]; + return type ? *type->destroy(node) : nullptr; + } + + static void tick(size_t node, double dT) { + for (auto& it : _type_list()) { + it->tick(node, dT); + } + } + + static void frame(size_t node, uint64_t f) { + for (auto& it : _type_list()) { + it->tick(node, f); + } + } + + static const auto& type_list() { return _type_list(); } + +// MEMBERS ============================================================================================================= +public: + const type_info* type; + const size_t node; + + template + component(size_t node) + : type(type_list()[uuid()]) + , node(node) { + } }; } diff --git a/include/fennec/scene/scene.h b/include/fennec/scene/scene.h index 64a1fee..c15de22 100644 --- a/include/fennec/scene/scene.h +++ b/include/fennec/scene/scene.h @@ -18,6 +18,7 @@ #ifndef FENNEC_CORE_SCENE_H #define FENNEC_CORE_SCENE_H + #include #include diff --git a/planning/CONTAINERS.md b/planning/CONTAINERS.md index d4d2a1a..544ff76 100644 --- a/planning/CONTAINERS.md +++ b/planning/CONTAINERS.md @@ -51,5 +51,5 @@ Library and Template Library. | Symbol | Implemented | Passed | |:--------|:-----------:|:------:| -| graph | ✔ | ✔ | +| graph | ❌ | ❌ | | rd_tree | ✔ | ✔ |