...
This commit is contained in:
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user