This commit is contained in:
2026-05-27 16:18:11 +03:00
parent e9c329d88f
commit 3497850e1f

View File

@@ -137,7 +137,12 @@ public:
static constexpr size_t NUMBER_OF_RECORDS = std::tuple_size_v<DESCR_T>; static constexpr size_t NUMBER_OF_RECORDS = std::tuple_size_v<DESCR_T>;
MccKeyValueHolder(DESCR_T desc) : _keyValue(desc) MccKeyValueHolder(DESCR_T desc)
: _keyValue(desc), _mapHash{[&desc]<size_t... Is>(std::index_sequence<Is...>) {
auto arr = std::array{std::make_pair(utils::FNV1aHash(std::get<Is>(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<NUMBER_OF_RECORDS>())}
{ {
[this]<size_t... I>(std::index_sequence<I...>) { [this]<size_t... I>(std::index_sequence<I...>) {
((_hashes[I] = utils::FNV1aHash(std::get<I>(_keyValue).key)), ...); ((_hashes[I] = utils::FNV1aHash(std::get<I>(_keyValue).key)), ...);
@@ -171,25 +176,34 @@ public:
template <typename T> template <typename T>
std::expected<T, std::error_code> getValue(std::string_view key) const std::expected<T, std::error_code> getValue(std::string_view key) const
{ {
T v; // T v;
auto err = forKey(key, [&v](auto const& rec) -> std::error_code { // auto err = forKey(key, [&v](auto const& rec) -> std::error_code {
// using VT = decltype(rec.value);
// if constexpr (std::convertible_to<VT, T>) {
// v = rec.value;
// } else if constexpr (std::constructible_from<T, VT>) {
// 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); using VT = decltype(rec.value);
if constexpr (std::convertible_to<VT, T>) { if constexpr (std::constructible_from<T, VT>) {
v = rec.value; return T{rec.value};
} else if constexpr (std::constructible_from<T, VT>) {
v = T(rec.value);
} else { } 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 <std::ranges::contiguous_range R, typename T> template <std::ranges::contiguous_range R, typename T>
@@ -401,6 +415,8 @@ protected:
std::unordered_map<size_t, std::string> _inlineComment{}; // inline (after key=value pair) comment std::unordered_map<size_t, std::string> _inlineComment{}; // inline (after key=value pair) comment
std::unordered_set<size_t> _changedKey{}; // loaded keys (see fromCharRange) std::unordered_set<size_t> _changedKey{}; // loaded keys (see fromCharRange)
const std::array<std::pair<size_t, size_t>, NUMBER_OF_RECORDS> _mapHash;
// //
// NOTE: deduced this is needed here to use "forKey" method in getter and setter (const and non-const contexts)!!! // 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; return MccKeyValueHolderErrorCode::ERROR_INVALID_KEY;
} }
template <typename FuncT>
auto forHash1(this auto&& self, size_t hash, FuncT&& func)
{
return std::forward<decltype(self)>(self).template forHash1Impl<NUMBER_OF_RECORDS / 2>(
hash, std::forward<FuncT>(func), 0, NUMBER_OF_RECORDS - 1);
}
//
// implements a binary search
//
template <size_t I = NUMBER_OF_RECORDS / 2, typename FuncT>
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<FuncT>;
if constexpr (I < NUMBER_OF_RECORDS) {
if (hash == std::forward<decltype(self)>(self)._mapHash[I].first) {
constexpr auto idx = std::forward<decltype(self)>(self)._mapHash[I].second;
using rec_t = std::tuple_element_t<idx, DESCR_T>;
if constexpr (std::is_void_v<std::invoke_result_t<func_t, rec_t>>) {
std::forward<FuncT>(func)(std::get<idx>(std::forward<decltype(self)>(self)._keyValue));
} else {
return std::forward<FuncT>(func)(std::get<idx>(std::forward<decltype(self)>(self)._keyValue));
}
} else if (hash < std::forward<decltype(self)>(self)._mapHash[I].first) {
if (stop - start > 1) {
return std::forward<decltype(self)>(self).template forHash1Impl<I / 2>(
hash, std::forward<FuncT>(func), start, I - 1);
}
const auto idx = self._mapHash[I - 1].second;
using rec_t = std::tuple_element_t<idx, DESCR_T>;
if constexpr (std::is_void_v<std::invoke_result_t<func_t, rec_t>>) {
std::forward<FuncT>(func)(std::get<idx>(std::forward<decltype(self)>(self)._keyValue));
} else {
return std::forward<FuncT>(func)(std::get<idx>(std::forward<decltype(self)>(self)._keyValue));
}
} else { // hash > std::forward<decltype(self)>(self)._mapHash[I].first
if (stop - start > 1) {
return std::forward<decltype(self)>(self).template forHash1Impl<I / 2>(
hash, std::forward<FuncT>(func), I + 1, stop);
}
const auto idx = self._mapHash[I + 1].second;
using rec_t = std::tuple_element_t<idx, DESCR_T>;
if constexpr (std::is_void_v<std::invoke_result_t<func_t, rec_t>>) {
std::forward<FuncT>(func)(std::get<idx>(std::forward<decltype(self)>(self)._keyValue));
} else {
return std::forward<FuncT>(func)(std::get<idx>(std::forward<decltype(self)>(self)._keyValue));
}
}
}
}
template <size_t I = 0, traits::mcc_output_char_range R, traits::mcc_input_char_range RecDelimT> template <size_t I = 0, traits::mcc_output_char_range R, traits::mcc_input_char_range RecDelimT>
std::error_code formatRecord(R& output_buffer, RecDelimT rec_delim, bool is_default = false) std::error_code formatRecord(R& output_buffer, RecDelimT rec_delim, bool is_default = false)
{ {