diff --git a/headers/Containers/DualkeyMap.hpp b/headers/Containers/DualkeyMap.hpp index 2f128c2..a64f09d 100644 --- a/headers/Containers/DualkeyMap.hpp +++ b/headers/Containers/DualkeyMap.hpp @@ -11,69 +11,88 @@ #include "../Systems/Logging.hpp" #include "Hashing.hpp" +#include #include #include #include #include -#include #include #include #include namespace Tourmaline::Containers { template + uint64_t baseReservation = 2048> class DualkeyMap { - DualkeyMap() { HashList.reserve(baseReservation); } +public: + using ResultPair = + std::pair, + std::reference_wrapper>, + Value &>; + DualkeyMap() { HashList.reserve(baseReservation); } ~DualkeyMap() { // I'm sure there is a better way to do this - for (DualkeyHash hash : HashList) { - delete hash.Apointer; - delete hash.Bpointer; - delete hash.ValuePointer; + for (DualkeyHash *hash : HashList) { + delete hash; } } - std::span, Value &>> - operator[](std::optional FirstKey, std::optional SecondKey) { - bool isFirstKeyGiven = FirstKey.has_value(); - bool isSecondKeyGiven = SecondKey.has_value(); + // Insertion + void Insert(AKey firstKey, BKey secondKey, Value value) { + std::size_t firstKeyHash = std::hash{}(firstKey); + std::size_t secondKeyHash = std::hash{}(secondKey); + HashList.push_back(new DualkeyHash(firstKeyHash, std::move(firstKey), + secondKeyHash, std::move(secondKey), + std::move(value))); + } + + // Indexing + std::vector Query(std::optional firstKey, + std::optional secondKey) { + bool isFirstKeyGiven = firstKey.has_value(); + bool isSecondKeyGiven = secondKey.has_value(); if (!isFirstKeyGiven && !isSecondKeyGiven) [[unlikely]] { Systems::Logging::Log("Failed to index! Dualkey maps require at least 1 " - "key to be given, returning an empty span.", + "key to be given, returning an empty vector.", "Dualkey Map", Systems::Logging::LogLevel::Warning); return {}; } std::size_t firstKeyHash = - isFirstKeyGiven ? std::hash{}(*FirstKey.value()) : 0; + isFirstKeyGiven ? std::hash{}(firstKey.value()) : 0; std::size_t secondKeyHash = - isSecondKeyGiven ? std::hash{}(*SecondKey.value()) : 0; + isSecondKeyGiven ? std::hash{}(secondKey.value()) : 0; - std::vector< - std::pair, Value &>> - finishedQuery{}; + std::vector finishedQuery{}; uint8_t stateOfIndexing = isFirstKeyGiven + (isSecondKeyGiven << 1); - for (DualkeyHash hash : HashList) { + // Putting hash checks first to benefit from short circuits + for (DualkeyHash *hash : HashList) { switch (stateOfIndexing) { case 1: // Only first key is given - if (firstKeyHash == hash.AKeyHash) { - finishedQuery.emplace_back(hash.BPointer, hash.ValuePointer); + if (firstKeyHash == hash->firstKeyHash && + firstKey.value() == hash->firstKey) { + finishedQuery.emplace_back( + std::reference_wrapper{hash->secondKey}, hash->value); } continue; case 2: // Only second key is given - if (secondKeyHash == hash.BKeyHash) { - finishedQuery.emplace_back(hash.APointer, hash.ValuePointer); + if (secondKeyHash == hash->secondKeyHash && + secondKey.value() == hash->secondKey) { + finishedQuery.emplace_back( + std::reference_wrapper{hash->firstKey}, hash->value); } continue; case 3: // Both are given - if (firstKeyHash == hash.AKeyHash && secondKeyHash == hash.BKeyHash) { - finishedQuery.emplace_back(std::monostate{}, hash.ValuePointer); + if (firstKeyHash == hash->firstKeyHash && + secondKeyHash == hash->secondKeyHash && + firstKey.value() == hash->firstKey && + secondKey.value() == hash->secondKey) { + finishedQuery.emplace_back(std::monostate{}, hash->value); + break; } - break; + continue; } break; } @@ -90,18 +109,21 @@ class DualkeyMap { private: struct DualkeyHash { - DualkeyHash(std::size_t AHash, AKey *APointer, std::size_t BHash, - BKey *BPointer) - : AKeyHash(AHash), APointer(APointer), BKeyHash(BHash), - BPointer(BPointer) {} - std::size_t AKeyHash = 0; - std::size_t BKeyHash = 0; - AKey *APointer; - BKey *BPointer; - Value *ValuePointer; + DualkeyHash(std::size_t firstKeyHash, AKey &&firstKey, + std::size_t secondKeyHash, BKey &&secondKey, Value &&value) + : firstKeyHash(firstKeyHash), firstKey(std::move(firstKey)), + secondKeyHash(secondKeyHash), secondKey(std::move(secondKey)), + value(std::move(value)) {} + + std::size_t firstKeyHash = 0; + std::size_t secondKeyHash = 0; + AKey firstKey; + BKey secondKey; + Value value; }; - std::vector HashList; + // It makes more sense to store the individual hash + std::vector HashList; }; } // namespace Tourmaline::Containers #endif diff --git a/headers/Containers/Hashing.hpp b/headers/Containers/Hashing.hpp index d402fe4..7af88cf 100644 --- a/headers/Containers/Hashing.hpp +++ b/headers/Containers/Hashing.hpp @@ -15,7 +15,7 @@ namespace Tourmaline::Containers { template concept Hashable = requires(T x) { - { std::hash{x}() } -> std::convertible_to; + { std::hash{}(x) } -> std::convertible_to; }; } // namespace Tourmaline::Containers #endif