...
This commit is contained in:
@@ -137,7 +137,12 @@ public:
|
||||
|
||||
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...>) {
|
||||
((_hashes[I] = utils::FNV1aHash(std::get<I>(_keyValue).key)), ...);
|
||||
@@ -171,25 +176,34 @@ public:
|
||||
template <typename T>
|
||||
std::expected<T, std::error_code> 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<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);
|
||||
if constexpr (std::convertible_to<VT, T>) {
|
||||
v = rec.value;
|
||||
} else if constexpr (std::constructible_from<T, VT>) {
|
||||
v = T(rec.value);
|
||||
if constexpr (std::constructible_from<T, VT>) {
|
||||
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 <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_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)!!!
|
||||
//
|
||||
@@ -434,6 +450,67 @@ protected:
|
||||
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>
|
||||
std::error_code formatRecord(R& output_buffer, RecDelimT rec_delim, bool is_default = false)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user