From 3497850e1fbb75bb46094731dabf6f9dd209a86c Mon Sep 17 00:00:00 2001 From: "Timur A. Fatkhullin" Date: Wed, 27 May 2026 16:18:11 +0300 Subject: [PATCH] ... --- include/mcc/mcc_keyvalue.h | 109 +++++++++++++++++++++++++++++++------ 1 file changed, 93 insertions(+), 16 deletions(-) diff --git a/include/mcc/mcc_keyvalue.h b/include/mcc/mcc_keyvalue.h index 5d92e72..c5a5f38 100644 --- a/include/mcc/mcc_keyvalue.h +++ b/include/mcc/mcc_keyvalue.h @@ -137,7 +137,12 @@ public: static constexpr size_t NUMBER_OF_RECORDS = std::tuple_size_v; - MccKeyValueHolder(DESCR_T desc) : _keyValue(desc) + MccKeyValueHolder(DESCR_T desc) + : _keyValue(desc), _mapHash{[&desc](std::index_sequence) { + auto arr = std::array{std::make_pair(utils::FNV1aHash(std::get(desc).key), Is)...}; + std::sort(arr.begin(), arr.end(), [](auto const& p1, auto const& p2) { return p1.first < p2.first; }); + return arr; + }(std::make_index_sequence())} { [this](std::index_sequence) { ((_hashes[I] = utils::FNV1aHash(std::get(_keyValue).key)), ...); @@ -171,25 +176,34 @@ public: template std::expected getValue(std::string_view key) const { - T v; - auto err = forKey(key, [&v](auto const& rec) -> std::error_code { + // T v; + // auto err = forKey(key, [&v](auto const& rec) -> std::error_code { + // using VT = decltype(rec.value); + // if constexpr (std::convertible_to) { + // v = rec.value; + // } else if constexpr (std::constructible_from) { + // v = T(rec.value); + // } else { + // return MccKeyValueHolderErrorCode::ERROR_INCOMPATIBLE_TYPE; + // } + + // return MccKeyValueHolderErrorCode::ERROR_OK; + // }); + + // if (err) { + // return std::unexpected(err); + // } else { + // return v; + // } + + return forHash1(utils::FNV1aHash(key), [](auto const& rec) { using VT = decltype(rec.value); - if constexpr (std::convertible_to) { - v = rec.value; - } else if constexpr (std::constructible_from) { - v = T(rec.value); + if constexpr (std::constructible_from) { + return T{rec.value}; } else { - return MccKeyValueHolderErrorCode::ERROR_INCOMPATIBLE_TYPE; + return std::unexpected(MccKeyValueHolderErrorCode::ERROR_INCOMPATIBLE_TYPE); } - - return MccKeyValueHolderErrorCode::ERROR_OK; }); - - if (err) { - return std::unexpected(err); - } else { - return v; - } } template @@ -401,6 +415,8 @@ protected: std::unordered_map _inlineComment{}; // inline (after key=value pair) comment std::unordered_set _changedKey{}; // loaded keys (see fromCharRange) + const std::array, NUMBER_OF_RECORDS> _mapHash; + // // NOTE: deduced this is needed here to use "forKey" method in getter and setter (const and non-const contexts)!!! // @@ -434,6 +450,67 @@ protected: return MccKeyValueHolderErrorCode::ERROR_INVALID_KEY; } + template + auto forHash1(this auto&& self, size_t hash, FuncT&& func) + { + return std::forward(self).template forHash1Impl( + hash, std::forward(func), 0, NUMBER_OF_RECORDS - 1); + } + + // + // implements a binary search + // + template + auto forHash1Impl(this auto&& self, + size_t hash, + FuncT&& func, + size_t start = 0, + size_t stop = NUMBER_OF_RECORDS - 1) + { + using func_t = std::remove_cvref_t; + + if constexpr (I < NUMBER_OF_RECORDS) { + if (hash == std::forward(self)._mapHash[I].first) { + constexpr auto idx = std::forward(self)._mapHash[I].second; + using rec_t = std::tuple_element_t; + + if constexpr (std::is_void_v>) { + std::forward(func)(std::get(std::forward(self)._keyValue)); + } else { + return std::forward(func)(std::get(std::forward(self)._keyValue)); + } + } else if (hash < std::forward(self)._mapHash[I].first) { + if (stop - start > 1) { + return std::forward(self).template forHash1Impl( + hash, std::forward(func), start, I - 1); + } + + const auto idx = self._mapHash[I - 1].second; + using rec_t = std::tuple_element_t; + + if constexpr (std::is_void_v>) { + std::forward(func)(std::get(std::forward(self)._keyValue)); + } else { + return std::forward(func)(std::get(std::forward(self)._keyValue)); + } + } else { // hash > std::forward(self)._mapHash[I].first + if (stop - start > 1) { + return std::forward(self).template forHash1Impl( + hash, std::forward(func), I + 1, stop); + } + + const auto idx = self._mapHash[I + 1].second; + using rec_t = std::tuple_element_t; + + if constexpr (std::is_void_v>) { + std::forward(func)(std::get(std::forward(self)._keyValue)); + } else { + return std::forward(func)(std::get(std::forward(self)._keyValue)); + } + } + } + } + template std::error_code formatRecord(R& output_buffer, RecDelimT rec_delim, bool is_default = false) {