Added more proper fails and QueryWithAll first iteration (not fully impl)

This commit is contained in:
2026-02-15 04:15:59 +02:00
parent bd3be51abd
commit f20e75a9ee

View File

@@ -11,20 +11,24 @@
#include "../Systems/Logging.hpp" #include "../Systems/Logging.hpp"
#include "Hashing.hpp" #include "Hashing.hpp"
#include <array>
#include <cmath> #include <cmath>
#include <concepts>
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <format>
#include <functional> #include <functional>
#include <optional> #include <optional>
#include <stack> #include <stack>
#include <tuple> #include <tuple>
#include <type_traits>
#include <utility> #include <utility>
#include <variant> #include <variant>
#include <vector> #include <vector>
namespace Tourmaline::Containers { namespace Tourmaline::Containers {
template <Hashable AKey, Hashable BKey, typename Value, template <Hashable AKey, Hashable BKey, typename Value,
uint64_t baseReservation = 2048, double maxTombstoneRatio = 0.25> uint64_t baseReservation = 2048>
class DualkeyMap { class DualkeyMap {
public: public:
using QueryResult = using QueryResult =
@@ -63,10 +67,10 @@ public:
bool isSecondKeyGiven = secondKey.has_value(); bool isSecondKeyGiven = secondKey.has_value();
if (!isFirstKeyGiven && !isSecondKeyGiven) [[unlikely]] { if (!isFirstKeyGiven && !isSecondKeyGiven) [[unlikely]] {
Systems::Logging::Log("Failed to Delete! Dualkey maps require at least 1 " Systems::Logging::Log(
"key to be given, doing nothing.", "Failed to Delete! DualkeyMap::Delete require at least 1 "
"Dualkey Map", Systems::Logging::LogLevel::Warning); "key to be given! Terminating",
return 0; "Dualkey Map", Systems::Logging::LogLevel::Critical);
} }
std::size_t firstKeyHash = std::size_t firstKeyHash =
@@ -126,10 +130,10 @@ public:
bool isSecondKeyGiven = secondKey.has_value(); bool isSecondKeyGiven = secondKey.has_value();
if (!isFirstKeyGiven && !isSecondKeyGiven) [[unlikely]] { if (!isFirstKeyGiven && !isSecondKeyGiven) [[unlikely]] {
Systems::Logging::Log("Failed to Query! Dualkey maps require at least 1 " Systems::Logging::Log(
"key to be given, returning an empty vector.", "Failed to Query! DualkeyMap::Query require at least 1 "
"Dualkey Map", Systems::Logging::LogLevel::Warning); "key to be given! Terminating",
return {}; "Dualkey Map", Systems::Logging::LogLevel::Critical);
} }
std::size_t firstKeyHash = std::size_t firstKeyHash =
isFirstKeyGiven ? std::hash<AKey>{}(firstKey.value()) : 0; isFirstKeyGiven ? std::hash<AKey>{}(firstKey.value()) : 0;
@@ -175,6 +179,93 @@ public:
return finishedQuery; return finishedQuery;
} }
template <typename Key, std::size_t keyCount>
requires(std::same_as<Key, AKey> || std::same_as<Key, BKey>)
[[nodiscard("Discarding a very expensive query!")]]
int QueryWithAll(const Key (&keys)[keyCount]) {
constexpr bool searchingInFirstKey = std::is_same_v<Key, AKey>;
// I really can't wait for C++26 contracts
if constexpr (keyCount == 0) {
Systems::Logging::Log("Failed to Query! QueryWithAll require at least 2 "
"key to be given, zero was given! Terminating",
"Dualkey Map",
Systems::Logging::LogLevel::Critical);
}
// Hoping this never ever gets triggered :sigh:
if constexpr (keyCount == 1) {
Systems::Logging::Log("QueryWithAll should not be used for single key "
"entry! Please use Query for this instead.",
"Dualkey Map", Systems::Logging::LogLevel::Error);
}
// While we don't necessary need the hashes,
// it just helps us tremendously benefit from short circuit checks
std::array<std::size_t, keyCount> keyHashes;
for (uint64_t index = 0; index < keyCount; index++) {
keyHashes[index] = std::hash<Key>{}(keys[index]);
}
std::vector<MultiQueryResult<
std::conditional_t<searchingInFirstKey, BKey, AKey>, keyCount>>
queryResults;
uint64_t hashToCompare;
Key *keyToCompare;
std::conditional_t<searchingInFirstKey, BKey *, AKey *> resultKey;
for (DualkeyHash *hash : hashList) {
// The hell of doing 2 conditions with similar logics in
// the same logical block
if constexpr (searchingInFirstKey) {
hashToCompare = hash->firstKeyHash;
keyToCompare = const_cast<AKey *>(&hash->firstKey);
resultKey = const_cast<BKey *>(&hash->secondKey);
} else {
hashToCompare = hash->secondKeyHash;
keyToCompare = const_cast<BKey *>(&hash->secondKey);
resultKey = const_cast<AKey *>(&hash->firstKey);
}
// 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) {
bool doesExist = false;
for (auto &queryRecord : queryResults) {
if (*queryRecord.resultKey == *resultKey) {
queryRecord.valueQueryResults[index] = &hash->value;
++queryRecord.howManyFound;
doesExist = true;
break;
}
}
if (doesExist) {
break;
}
// Since the result record is not present
// we have to make it
queryResults.emplace_back();
auto &newRecord = queryResults.back();
newRecord.resultKey = resultKey;
newRecord.valueQueryResults[index] = &hash->value;
}
}
}
for (const auto &queryRecord : queryResults) {
Systems::Logging::Log(
std::format("Opposite = {}, found = {}",
reinterpret_cast<uint64_t>(queryRecord.resultKey),
queryRecord.howManyFound),
"DKM", Systems::Logging::LogLevel::Info,
queryRecord.howManyFound == keyCount);
}
return 0;
}
void Scan(std::function<bool(const std::size_t firstKeyHash, void Scan(std::function<bool(const std::size_t firstKeyHash,
const std::size_t secondKeyHash, Value &value)> const std::size_t secondKeyHash, Value &value)>
scanFunction) { scanFunction) {
@@ -212,6 +303,13 @@ public:
DualkeyMap &operator=(const DualkeyMap &) = delete; DualkeyMap &operator=(const DualkeyMap &) = delete;
private: private:
template <typename OppositeKey, std::size_t keyCount>
struct MultiQueryResult {
OppositeKey *resultKey = nullptr;
std::size_t howManyFound = 1;
std::array<Value *, keyCount> valueQueryResults;
};
struct DualkeyHash { struct DualkeyHash {
DualkeyHash(AKey &&firstKey, BKey &&secondKey, Value &&value) DualkeyHash(AKey &&firstKey, BKey &&secondKey, Value &&value)
: firstKey(std::move(firstKey)), secondKey(std::move(secondKey)), : firstKey(std::move(firstKey)), secondKey(std::move(secondKey)),