diff --git a/src/Dynamo.hpp b/src/Dynamo.hpp index 366dcc9..b09fdb8 100644 --- a/src/Dynamo.hpp +++ b/src/Dynamo.hpp @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Graphics/Material.hpp b/src/Graphics/Material.hpp index adf9753..12f4578 100644 --- a/src/Graphics/Material.hpp +++ b/src/Graphics/Material.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include +#include namespace Dynamo::Graphics { /** diff --git a/src/Graphics/Mesh.hpp b/src/Graphics/Mesh.hpp index 87ed407..e4d9ef5 100644 --- a/src/Graphics/Mesh.hpp +++ b/src/Graphics/Mesh.hpp @@ -2,7 +2,7 @@ #include -#include +#include namespace Dynamo::Graphics { /** diff --git a/src/Graphics/Model.hpp b/src/Graphics/Model.hpp index e86c454..14ed623 100644 --- a/src/Graphics/Model.hpp +++ b/src/Graphics/Model.hpp @@ -2,7 +2,7 @@ #include #include -#include +#include namespace Dynamo::Graphics { /** diff --git a/src/Graphics/Shader.hpp b/src/Graphics/Shader.hpp index 3d07f88..24531e7 100644 --- a/src/Graphics/Shader.hpp +++ b/src/Graphics/Shader.hpp @@ -2,7 +2,7 @@ #include -#include +#include namespace Dynamo::Graphics { /** diff --git a/src/Graphics/Vulkan/MeshSet.cpp b/src/Graphics/Vulkan/MeshSet.cpp index 468d7e3..2c72dab 100644 --- a/src/Graphics/Vulkan/MeshSet.cpp +++ b/src/Graphics/Vulkan/MeshSet.cpp @@ -78,22 +78,21 @@ namespace Dynamo::Graphics::Vulkan { } // Register the allocation - Mesh mesh = _ids.generate(); - _allocations.insert(mesh, allocation); + Mesh mesh = IdGenerator::generate(); + _allocations.emplace(mesh, allocation); return mesh; } - MeshAllocation &MeshSet::get(Mesh mesh) { return _allocations.get(mesh); } + MeshAllocation &MeshSet::get(Mesh mesh) { return _allocations.at(mesh); } void MeshSet::free(Mesh mesh, Buffer &vertex_buffer, Buffer &index_buffer) { - MeshAllocation &allocation = _allocations.get(mesh); + MeshAllocation &allocation = _allocations.at(mesh); for (unsigned offset : allocation.attribute_offsets) { vertex_buffer.free(offset); } if (allocation.index_type != VK_INDEX_TYPE_NONE_KHR) { index_buffer.free(allocation.index_offset); } - _allocations.remove(mesh); - _ids.discard(mesh); + _allocations.erase(mesh); } } // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/MeshSet.hpp b/src/Graphics/Vulkan/MeshSet.hpp index f0e63eb..0f03cad 100644 --- a/src/Graphics/Vulkan/MeshSet.hpp +++ b/src/Graphics/Vulkan/MeshSet.hpp @@ -1,13 +1,13 @@ #pragma once +#include #include #include #include #include -#include -#include +#include namespace Dynamo::Graphics::Vulkan { /** @@ -29,8 +29,7 @@ namespace Dynamo::Graphics::Vulkan { * */ class MeshSet { - IdTracker _ids; - SparseSet _allocations; + std::unordered_map _allocations; public: /** diff --git a/src/Graphics/Vulkan/ShaderSet.cpp b/src/Graphics/Vulkan/ShaderSet.cpp index f0ee06e..0ed951d 100644 --- a/src/Graphics/Vulkan/ShaderSet.cpp +++ b/src/Graphics/Vulkan/ShaderSet.cpp @@ -216,18 +216,17 @@ namespace Dynamo::Graphics::Vulkan { Log::info(""); // Register the new shader - Shader shader = _ids.generate(); - _modules.insert(shader, module); + Shader shader = IdGenerator::generate(); + _modules.emplace(shader, module); return shader; } - const ShaderModule &ShaderSet::get(Shader shader) const { return _modules.get(shader); } + const ShaderModule &ShaderSet::get(Shader shader) const { return _modules.at(shader); } void ShaderSet::destroy(Shader shader) { - ShaderModule &module = _modules.get(shader); + ShaderModule &module = _modules.at(shader); vkDestroyShaderModule(_device, module.handle, nullptr); - _modules.remove(shader); - _ids.discard(shader); + _modules.erase(shader); } void ShaderSet::destroy() { @@ -236,10 +235,9 @@ namespace Dynamo::Graphics::Vulkan { } _descriptor_layouts.clear(); - for (ShaderModule &module : _modules) { + for (const auto &[key, module] : _modules) { vkDestroyShaderModule(_device, module.handle, nullptr); } _modules.clear(); - _ids.clear(); } } // namespace Dynamo::Graphics::Vulkan \ No newline at end of file diff --git a/src/Graphics/Vulkan/ShaderSet.hpp b/src/Graphics/Vulkan/ShaderSet.hpp index 31b3bb7..de10dea 100644 --- a/src/Graphics/Vulkan/ShaderSet.hpp +++ b/src/Graphics/Vulkan/ShaderSet.hpp @@ -1,13 +1,13 @@ #pragma once #include +#include #include #include #include #include -#include namespace Dynamo::Graphics::Vulkan { /** @@ -71,8 +71,7 @@ namespace Dynamo::Graphics::Vulkan { */ class ShaderSet { VkDevice _device; - IdTracker _ids; - SparseSet _modules; + std::unordered_map _modules; std::unordered_map _descriptor_layouts; /** diff --git a/src/Sound/Jukebox.hpp b/src/Sound/Jukebox.hpp index 8ebd855..1f2df2b 100644 --- a/src/Sound/Jukebox.hpp +++ b/src/Sound/Jukebox.hpp @@ -4,7 +4,6 @@ #include -#include #include #include diff --git a/src/Sound/Listener.hpp b/src/Sound/Listener.hpp index ed12e62..3106652 100644 --- a/src/Sound/Listener.hpp +++ b/src/Sound/Listener.hpp @@ -4,8 +4,6 @@ #include #include -#include -#include namespace Dynamo::Sound { /** diff --git a/src/Utils/IdGenerator.hpp b/src/Utils/IdGenerator.hpp new file mode 100644 index 0000000..72b018c --- /dev/null +++ b/src/Utils/IdGenerator.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include +#include + +#define DYN_DEFINE_ID_TYPE(T) using T = struct T##_t * + +namespace Dynamo { + /** + * @brief Generate typesafe handles. + * + * @tparam Id + */ + template + class IdGenerator { + static_assert(std::is_pointer::value, "Id must be a valid handle type (opaque pointer)."); + static_assert(sizeof(Id) == sizeof(uintptr_t), "Id and its integer mode must be the same size."); + static inline uintptr_t _counter = 0; + + public: + /** + * @brief Generate an id. + * + * @return Id + */ + static inline Id generate() { return reinterpret_cast(_counter++); } + + /** + * @brief Get the key of the id. + * + * @param id + * @return uintptr_t + */ + static inline uintptr_t key(Id id) { return reinterpret_cast(id); } + }; +} // namespace Dynamo \ No newline at end of file diff --git a/src/Utils/IdTracker.hpp b/src/Utils/IdTracker.hpp deleted file mode 100644 index a6e3d77..0000000 --- a/src/Utils/IdTracker.hpp +++ /dev/null @@ -1,119 +0,0 @@ -#pragma once - -#include -#include -#include - -#define DYN_DEFINE_ID_TYPE(T) using T = struct T##_t * - -static_assert(sizeof(void *) == sizeof(uintptr_t), "Pointer and its integer mode must be same size."); - -namespace Dynamo { - /** - * @brief Id index shift. - * - */ - constexpr unsigned long long ID_INDEX_SHIFT = (sizeof(uintptr_t) * 8) >> 1; - - /** - * @brief Id version mask. - * - */ - constexpr unsigned long long ID_VERSION_MASK = (1ULL << ID_INDEX_SHIFT) - 1; - - /** - * @brief Generate and discard typesafe handles. - * - * @tparam Id - */ - template - class IdTracker { - unsigned _index_counter; - - std::vector _version_map; - std::queue _free_indices; - - public: - /** - * @brief Construct a new IdTracker object. - * - */ - IdTracker() : _index_counter(0) {} - - /** - * @brief Get the index of an id. - * - * @param id - * @return unsigned - */ - static inline unsigned get_index(Id id) { return reinterpret_cast(id) >> ID_INDEX_SHIFT; } - - /** - * @brief Get the version of an id. - * - * @param id - * @return unsigned - */ - static inline unsigned get_version(Id id) { return reinterpret_cast(id) & ID_VERSION_MASK; } - - /** - * @brief Test if an id is active. - * - * @param id - * @return true - * @return false - */ - inline bool is_active(Id id) { - unsigned index = IdTracker::get_index(id); - unsigned version = IdTracker::get_version(id); - - return index < _index_counter && _version_map[index] == version; - } - - /** - * @brief Generate an id. - * - * This will recycle previously discarded ids if available. - * - * @return Id - */ - inline Id generate() { - unsigned index, version; - if (_free_indices.size() > 0) { - index = _free_indices.front(); - version = _version_map[index]; - _free_indices.pop(); - } else { - index = _index_counter++; - version = 0; - _version_map.push_back(version); - } - - // Move index to longer bitstring before compositing - uintptr_t id = index; - return reinterpret_cast((id << ID_INDEX_SHIFT) | version); - } - - /** - * @brief Discard an id. This will tag it as inactive and recyclable. - * - * @param id - */ - inline void discard(Id id) { - if (!is_active(id)) return; - unsigned index = IdTracker::get_index(id); - _version_map[index]++; - _free_indices.push(index); - } - - /** - * @brief Clear the id pool. - * - */ - inline void clear() { - _index_counter = 0; - _version_map.clear(); - _free_indices = {}; - } - }; -} // namespace Dynamo \ No newline at end of file diff --git a/src/Utils/SparseSet.hpp b/src/Utils/SparseSet.hpp index c55396c..a3e320c 100644 --- a/src/Utils/SparseSet.hpp +++ b/src/Utils/SparseSet.hpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include namespace Dynamo { @@ -41,7 +41,7 @@ namespace Dynamo { * @brief Contains indices to _dense and _pool * */ - std::vector _sparse; + std::vector _sparse; public: /** @@ -66,14 +66,14 @@ namespace Dynamo { * @return int Index position of the value (-1 on failure). */ inline int find(Id id) const { - unsigned key = IdTracker::get_index(id); + uintptr_t key = IdGenerator::key(id); if (key >= _sparse.size()) { return -1; } // Verify that the sparse and dense arrays are correlated - int index = _sparse[key]; - int dense_size = _dense.size(); + uintptr_t index = _sparse[key]; + uintptr_t dense_size = _dense.size(); if (index == -1 || index >= dense_size || _dense[index] != id) { return -1; } @@ -101,7 +101,7 @@ namespace Dynamo { template inline void insert(Id id, Params... args) { // Resize the sparse array or remove the existing item - unsigned key = IdTracker::get_index(id); + uintptr_t key = IdGenerator::key(id); if (key >= _sparse.size()) { _sparse.resize((key + 1) * 2, -1); } else if (_sparse[key] != -1) { @@ -127,20 +127,20 @@ namespace Dynamo { * @param id Unique identifier of the object to be removed. */ inline void remove(Id id) { - unsigned key = IdTracker::get_index(id); + uintptr_t key = IdGenerator::key(id); if (key >= _sparse.size()) { return; } // Verify that the sparse and dense arrays are correlated - int index = _sparse[key]; - int dense_size = _dense.size(); + uintptr_t index = _sparse[key]; + uintptr_t dense_size = _dense.size(); if (index == -1 || index >= dense_size || _dense[index] != id) { return; } // Swap last element of dense and pool array to maintain contiguity - unsigned new_key = IdTracker::get_index(_dense.back()); + uintptr_t new_key = IdGenerator::key(_dense.back()); std::swap(_pool.back(), _pool[index]); _pool.pop_back(); diff --git a/tests/src/Utils/IdGenerator.cpp b/tests/src/Utils/IdGenerator.cpp new file mode 100644 index 0000000..124438e --- /dev/null +++ b/tests/src/Utils/IdGenerator.cpp @@ -0,0 +1,19 @@ +#include +#include + +DYN_DEFINE_ID_TYPE(Id_0); +DYN_DEFINE_ID_TYPE(Id_1); + +TEST_CASE("IdGenerator generate", "[IdGenerator]") { + Id_0 a0 = Dynamo::IdGenerator::generate(); + Id_0 b0 = Dynamo::IdGenerator::generate(); + + Id_1 a1 = Dynamo::IdGenerator::generate(); + Id_1 b1 = Dynamo::IdGenerator::generate(); + + REQUIRE(Dynamo::IdGenerator::key(a0) == 0); + REQUIRE(Dynamo::IdGenerator::key(b0) == 1); + + REQUIRE(Dynamo::IdGenerator::key(a1) == 0); + REQUIRE(Dynamo::IdGenerator::key(b1) == 1); +} diff --git a/tests/src/Utils/IdTracker.cpp b/tests/src/Utils/IdTracker.cpp deleted file mode 100644 index b3e9c72..0000000 --- a/tests/src/Utils/IdTracker.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include -#include - -DYN_DEFINE_ID_TYPE(Id); - -TEST_CASE("IdTracker get index and version", "[IdTracker]") { - uintptr_t index = 1; - index = (index << 32) - 1; - - uintptr_t version = 1; - version = (version << 31) - 10; - - Id id = reinterpret_cast((index << 32) | version); - REQUIRE(Dynamo::IdTracker::get_index(id) == index); - REQUIRE(Dynamo::IdTracker::get_version(id) == version); -} - -TEST_CASE("IdTracker generate", "[IdTracker]") { - Dynamo::IdTracker tracker; - Id a = tracker.generate(); - Id b = tracker.generate(); - - REQUIRE(Dynamo::IdTracker::get_index(a) == 0); - REQUIRE(Dynamo::IdTracker::get_version(a) == 0); - - REQUIRE(Dynamo::IdTracker::get_index(b) == 1); - REQUIRE(Dynamo::IdTracker::get_version(b) == 0); -} - -TEST_CASE("IdTracker discard", "[IdTracker]") { - Dynamo::IdTracker tracker; - Id a = tracker.generate(); - tracker.discard(a); - Id b = tracker.generate(); - tracker.discard(b); - Id c = tracker.generate(); - Id d = tracker.generate(); - - REQUIRE(Dynamo::IdTracker::get_index(a) == 0); - REQUIRE(Dynamo::IdTracker::get_version(a) == 0); - - REQUIRE(Dynamo::IdTracker::get_index(b) == 0); - REQUIRE(Dynamo::IdTracker::get_version(b) == 1); - - REQUIRE(Dynamo::IdTracker::get_index(c) == 0); - REQUIRE(Dynamo::IdTracker::get_version(c) == 2); - - REQUIRE(Dynamo::IdTracker::get_index(d) == 1); - REQUIRE(Dynamo::IdTracker::get_version(d) == 0); -} - -TEST_CASE("IdTracker is_active", "[IdTracker]") { - Dynamo::IdTracker tracker; - Id a = tracker.generate(); - - REQUIRE(tracker.is_active(a)); - tracker.discard(a); - REQUIRE(!tracker.is_active(a)); -} - -TEST_CASE("IdTracker clear", "[IdTracker]") { - Dynamo::IdTracker tracker; - for (int i = 0; i < 100; i++) { - tracker.generate(); - } - tracker.clear(); - - Id a = tracker.generate(); - REQUIRE(Dynamo::IdTracker::get_index(a) == 0); - REQUIRE(Dynamo::IdTracker::get_version(a) == 0); -} \ No newline at end of file diff --git a/tests/src/Utils/SparseSet.cpp b/tests/src/Utils/SparseSet.cpp index c6c66df..8594b62 100644 --- a/tests/src/Utils/SparseSet.cpp +++ b/tests/src/Utils/SparseSet.cpp @@ -7,11 +7,10 @@ using CharSet = Dynamo::SparseSet; TEST_CASE("SparseSet []", "[SparseSet]") { CharSet set; - Dynamo::IdTracker tracker; - set.insert(tracker.generate(), 'a'); - set.insert(tracker.generate(), 'b'); - set.insert(tracker.generate(), 'c'); + set.insert(Dynamo::IdGenerator::generate(), 'a'); + set.insert(Dynamo::IdGenerator::generate(), 'b'); + set.insert(Dynamo::IdGenerator::generate(), 'c'); REQUIRE(set[0] == 'a'); REQUIRE(set[1] == 'b'); @@ -20,11 +19,10 @@ TEST_CASE("SparseSet []", "[SparseSet]") { TEST_CASE("SparseSet const []", "[SparseSet]") { CharSet set; - Dynamo::IdTracker tracker; - set.insert(tracker.generate(), 'a'); - set.insert(tracker.generate(), 'b'); - set.insert(tracker.generate(), 'c'); + set.insert(Dynamo::IdGenerator::generate(), 'a'); + set.insert(Dynamo::IdGenerator::generate(), 'b'); + set.insert(Dynamo::IdGenerator::generate(), 'c'); const CharSet &const_set = set; @@ -35,11 +33,10 @@ TEST_CASE("SparseSet const []", "[SparseSet]") { TEST_CASE("SparseSet get", "[SparseSet]") { CharSet set; - Dynamo::IdTracker tracker; - Id a = tracker.generate(); - Id b = tracker.generate(); - Id c = tracker.generate(); + Id a = Dynamo::IdGenerator::generate(); + Id b = Dynamo::IdGenerator::generate(); + Id c = Dynamo::IdGenerator::generate(); set.insert(a, 'a'); set.insert(b, 'b'); @@ -52,11 +49,10 @@ TEST_CASE("SparseSet get", "[SparseSet]") { TEST_CASE("SparseSet const get", "[SparseSet]") { CharSet set; - Dynamo::IdTracker tracker; - Id a = tracker.generate(); - Id b = tracker.generate(); - Id c = tracker.generate(); + Id a = Dynamo::IdGenerator::generate(); + Id b = Dynamo::IdGenerator::generate(); + Id c = Dynamo::IdGenerator::generate(); set.insert(a, 'a'); set.insert(b, 'b'); @@ -71,17 +67,16 @@ TEST_CASE("SparseSet const get", "[SparseSet]") { TEST_CASE("SparseSet insert", "[SparseSet]") { CharSet set; - Dynamo::IdTracker tracker; - Id a = tracker.generate(); + Id a = Dynamo::IdGenerator::generate(); set.insert(a, 'a'); REQUIRE(set.get(a) == 'a'); - Id b = tracker.generate(); + Id b = Dynamo::IdGenerator::generate(); set.insert(b, 'b'); REQUIRE(set.get(b) == 'b'); - Id c = tracker.generate(); + Id c = Dynamo::IdGenerator::generate(); set.insert(c, 'c'); REQUIRE(set.get(c) == 'c'); @@ -91,9 +86,8 @@ TEST_CASE("SparseSet insert", "[SparseSet]") { TEST_CASE("SparseSet remove", "[SparseSet]") { CharSet set; - Dynamo::IdTracker tracker; - Id a = tracker.generate(); + Id a = Dynamo::IdGenerator::generate(); set.insert(a, 'a'); REQUIRE(set.find(a) == 0); REQUIRE(set.get(a) == 'a'); @@ -109,17 +103,16 @@ TEST_CASE("SparseSet remove", "[SparseSet]") { TEST_CASE("SparseSet clear", "[SparseSet]") { CharSet set; - Dynamo::IdTracker tracker; - Id a = tracker.generate(); + Id a = Dynamo::IdGenerator::generate(); set.insert(a, 'a'); REQUIRE(set.get(a) == 'a'); - Id b = tracker.generate(); + Id b = Dynamo::IdGenerator::generate(); set.insert(b, 'b'); REQUIRE(set.get(b) == 'b'); - Id c = tracker.generate(); + Id c = Dynamo::IdGenerator::generate(); set.insert(c, 'c'); REQUIRE(set.get(c) == 'c'); @@ -141,43 +134,23 @@ TEST_CASE("SparseSet clear", "[SparseSet]") { REQUIRE_THROWS(set.get(c)); } -TEST_CASE("SparseSet mismatched id version", "[SparseSet]") { - CharSet set; - Dynamo::IdTracker tracker; - - Id a = tracker.generate(); - set.insert(a, 'a'); - REQUIRE(set.get(a) == 'a'); - - tracker.discard(a); - Id b = tracker.generate(); - REQUIRE(Dynamo::IdTracker::get_index(a) == Dynamo::IdTracker::get_index(b)); - REQUIRE_THROWS(set.get(b)); - - set.insert(b, 'b'); - REQUIRE(set.get(b) == 'b'); - REQUIRE(set.size() == 1); - REQUIRE(!set.empty()); -} - TEST_CASE("SparseSet foreach", "[SparseSet]") { CharSet set; - Dynamo::IdTracker tracker; - Id a = tracker.generate(); + Id a = Dynamo::IdGenerator::generate(); set.insert(a, 'a'); REQUIRE(set.get(a) == 'a'); - Id b = tracker.generate(); + Id b = Dynamo::IdGenerator::generate(); set.insert(b, 'b'); REQUIRE(set.get(b) == 'b'); - Id c = tracker.generate(); + Id c = Dynamo::IdGenerator::generate(); set.insert(c, 'c'); REQUIRE(set.get(c) == 'c'); set.remove(a); - Id d = tracker.generate(); + Id d = Dynamo::IdGenerator::generate(); set.insert(d, 'd'); REQUIRE(set.size() == 3);