diff --git a/headers/Containers/ContainerOptions.hpp b/headers/Containers/ContainerOptions.hpp new file mode 100644 index 0000000..482a4bf --- /dev/null +++ b/headers/Containers/ContainerOptions.hpp @@ -0,0 +1,28 @@ +/* + * SPDX-FileCopyrightText: Dora "cat" + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + */ +#ifndef GUARD_TOURMALINE_CONTAINEROPTIONS_H +#define GUARD_TOURMALINE_CONTAINEROPTIONS_H + +#include +#include + +namespace Tourmaline::Containers { +struct HashmapOptions { + float loadFactor = 0.75f; + float minimizeFactor = 0.20f; + float leaningFactor = 2.5f; + std::size_t minimumBucketCount = 256; + std::size_t reservedBucketSpace = 4; +}; + +struct DualKeyMapOptions { + std::uint64_t baseReservation = 2048; +}; +} // namespace Tourmaline::Containers +#endif diff --git a/headers/Containers/DualkeyMap.hpp b/headers/Containers/DualkeyMap.hpp index da9fb0f..d708f5c 100644 --- a/headers/Containers/DualkeyMap.hpp +++ b/headers/Containers/DualkeyMap.hpp @@ -10,6 +10,7 @@ #define GUARD_TOURMALINE_DUALKEYMAP_H #include "../Concepts.hpp" #include "../Systems/Logging.hpp" +#include "ContainerOptions.hpp" #include "Hashmap.hpp" #include @@ -28,7 +29,7 @@ namespace Tourmaline::Containers { template + DualKeyMapOptions Options = {}> class DualkeyMap { public: // Return Types @@ -49,7 +50,7 @@ public: using Entry = std::tuple; // Construct/Destruct - DualkeyMap() { hashList.reserve(baseReservation); } + DualkeyMap() { hashList.reserve(Options.baseReservation); } ~DualkeyMap() { // I'm sure there is a better way to do this for (DualkeyHash *hash : hashList) { @@ -301,7 +302,7 @@ private: OppositeKey *oppositeKey; Containers::Hashmap, - 8.0f, 2048, 0.01f> // Aggressive hashmap :o + {8.0f, 0.01f, 2.5f, 2048, 8}> // Aggressive hashmap :o queryResults; for (DualkeyHash *hash : hashList) { @@ -325,7 +326,7 @@ private: // The code above was done to make this code more uniform for (uint64_t index = 0; index < keyCount; index++) { if (keyHashes[index] == hashToCompare && keys[index] == *keyToCompare) { - if (queryResults.Has(*oppositeKey)) { + if (queryResults.Has(*oppositeKey)) [[likely]] { auto &entry = queryResults.Get(*oppositeKey); entry.valueQueryResults[index] = &hash->value; ++entry.howManyFound; diff --git a/headers/Containers/Hashmap.hpp b/headers/Containers/Hashmap.hpp index 8db06ab..349d67d 100644 --- a/headers/Containers/Hashmap.hpp +++ b/headers/Containers/Hashmap.hpp @@ -10,20 +10,21 @@ #define GUARD_TOURMALINE_HASHMAP_H #include "../Concepts.hpp" #include "../Systems/Logging.hpp" +#include "ContainerOptions.hpp" #include #include namespace Tourmaline::Containers { -template +template class Hashmap { public: - Hashmap() { storage.resize(minimumBucketCount); } + Hashmap() { storage.resize(Options.minimumBucketCount); } ~Hashmap() { Clear(); } Value &Insert(Key key, Value value) { - if (currentLoadFactor >= loadFactor && currentlyRehashing == false) { + if (currentLoadFactor >= Options.loadFactor && + currentlyRehashing == false) { rehash(); } std::size_t keyHash = std::hash{}(key), @@ -35,6 +36,8 @@ public: Systems::Logging::Log("Trying to insert the same key twice! Throwing...", "Hashmap", Systems::Logging::LogLevel::Error, Has(key)); + } else { + storage[keyHashPosition].reserve(Options.reservedBucketSpace); } storage[keyHashPosition].emplace_back(key, std::move(value), keyHash); @@ -56,7 +59,7 @@ public: }); currentLoadFactor = (--count) / static_cast(bucketCount); - if (currentLoadFactor <= minimizeFactor) { + if (currentLoadFactor <= Options.minimizeFactor) { rehash(); } } @@ -113,7 +116,7 @@ public: } count = 0; - bucketCount = minimumBucketCount; + bucketCount = Options.minimumBucketCount; std::vector newStorage; storage.swap(newStorage); return result; @@ -134,16 +137,15 @@ private: // Minimum goalSize = goalSize == 0 ? count : goalSize; float wouldBeLoadFactor = goalSize / static_cast(bucketCount); - if (wouldBeLoadFactor < loadFactor && wouldBeLoadFactor > minimizeFactor) - [[unlikely]] { + if (wouldBeLoadFactor < Options.loadFactor && + wouldBeLoadFactor > Options.minimizeFactor) [[unlikely]] { return false; // No rehashing is required } // Putting it closer to minimizeFactor - std::size_t goalBucketCount = - goalSize / ((loadFactor + minimizeFactor) / 2.5); // Magic number - if (goalBucketCount < minimumBucketCount) [[unlikely]] { - goalBucketCount = minimumBucketCount; + std::size_t goalBucketCount = goalSize / preferredLoadFactor; + if (goalBucketCount < Options.minimumBucketCount) [[unlikely]] { + goalBucketCount = Options.minimumBucketCount; } // No need to reallocate @@ -181,8 +183,10 @@ private: using bucket = std::vector; std::vector storage; - std::size_t count = 0, bucketCount = minimumBucketCount; - float currentLoadFactor = 0; + std::size_t count = 0, bucketCount = Options.minimumBucketCount; + float currentLoadFactor = 0, + preferredLoadFactor = (Options.loadFactor + Options.minimizeFactor) / + Options.leaningFactor; bool currentlyRehashing = false; // Lock for Insert in rehash }; } // namespace Tourmaline::Containers diff --git a/source/Systems/ECS/World.cpp b/source/Systems/ECS/World.cpp index d540ad4..ca616b0 100644 --- a/source/Systems/ECS/World.cpp +++ b/source/Systems/ECS/World.cpp @@ -10,7 +10,6 @@ #include #include #include -#include using namespace Tourmaline::Systems; using namespace ECS;