This commit is contained in:
2025-10-06 12:09:06 +03:00
parent 9c13def8be
commit 58d62d85b3
3 changed files with 401 additions and 33 deletions

View File

@@ -427,6 +427,56 @@ public:
static constexpr std::string_view KEY_VALUE_DELIM{"="};
static constexpr std::string_view VALUE_ARRAY_DELIM{","};
inline static auto defaultDeserializeFunc = []<typename VT>(this auto&& self, std::string_view str, VT& value) {
std::error_code ret{};
if constexpr (std::is_arithmetic_v<VT>) {
auto v = mcc::utils::numFromStr<VT>(trimSpaces(str));
if (!v.has_value()) {
return std::make_error_code(std::errc::invalid_argument);
}
value = v.value();
} else if constexpr (mcc::traits::mcc_output_char_range<VT>) {
VT r;
std::ranges::copy(str, std::back_inserter(r));
value = r;
} else if constexpr (std::ranges::range<VT>) {
using el_t = std::ranges::range_value_t<VT>;
if constexpr (std::is_reference_v<el_t> || std::is_const_v<el_t>) { // no reference or constants allowed
return std::make_error_code(std::errc::invalid_argument);
}
VT r;
el_t elem;
auto els = std::views::split(str, VALUE_ARRAY_DELIM);
for (auto const& el : els) {
ret = std::forward<decltype(self)>(self)(std::string_view(el), elem);
if (!ret) {
std::back_inserter(r) = elem;
} else {
return std::make_error_code(std::errc::invalid_argument);
}
}
value = r;
} else if constexpr (mcc::traits::mcc_time_duration_c<VT>) {
typename VT::rep vd;
ret = std::forward<decltype(self)>(self)(trimSpaces(str), vd);
if (!ret) {
value = VT{vd};
}
} else {
ret = std::make_error_code(std::errc::invalid_argument);
}
return ret;
};
KeyValueHolder(DESCR_T desc) : _keyValue(desc)
{
[this]<size_t... I>(std::index_sequence<I...>) {
@@ -468,6 +518,12 @@ public:
}
template <std::ranges::contiguous_range R, std::ranges::input_range RecDelimT = std::string_view>
std::error_code fromCharRange(const R& buffer, RecDelimT rec_delim = std::string_view("\n"))
{
return fromCharRange(buffer, KeyValueHolder::defaultDeserializeFunc, std::move(rec_delim));
}
template <std::ranges::contiguous_range R,
typename DeserFuncT,
std::ranges::input_range RecDelimT = std::string_view>
@@ -475,6 +531,8 @@ public:
DeserFuncT&& deser_func,
RecDelimT rec_delim = std::string_view("\n"))
{
// static_assert(mcc::traits::mcc_callable_c<std::decay_t<DeserFuncT>>, "!!!!!!!");
if constexpr (std::is_array_v<std::decay_t<R>>) { // char*, const char*
if constexpr (std::is_array_v<std::decay_t<RecDelimT>>) {
return fromCharRange(std::string_view{buffer}, std::forward<DeserFuncT>(deser_func),
@@ -489,13 +547,19 @@ public:
}
}
auto parse_rec = [this, &deser_func](std::string_view rec) -> std::error_code {
std::string_view key, value;
std::error_code ec{};
std::string_view rec, key, value;
auto recs = std::views::split(buffer, std::move(rec_delim));
for (auto const& el : recs) {
rec = mcc::utils::trimSpaces(el, TrimType::TRIM_LEFT);
if (rec.size()) {
auto found = std::ranges::search(rec, COMMENT_SEQ);
if (found.begin() != rec.end()) { // there was the comment sequence in record
rec = rec.substr(std::distance(rec.begin(), found.begin()));
rec = std::string_view(rec.begin(), found.begin());
}
if (rec.size()) {
@@ -504,35 +568,17 @@ public:
key = trimSpaces(std::string_view(rec.begin(), found.begin()), TrimType::TRIM_RIGHT);
value = std::string_view(found.end(), rec.end());
return forKey(key, [value, &deser_func]<typename VT>(VT& v) { return deser_func(value, v); });
ec = forKey(key, [value, &deser_func]<typename VT>(VT& v) { return deser_func(value, v); });
}
}
} // just comment string starting from the beginning, just skip it (no error)
} // empty record, just skip it (no error)
if (ec) {
break;
}
};
auto curr_buffer = std::string_view(buffer.begin(), buffer.end());
bool buffer_end = false;
std::error_code ec;
std::string_view rec;
auto delim_size = std::ranges::size(rec_delim);
if (delim_size == 0) { // just one record
return parse_rec(trimSpaces(buffer, TrimType::TRIM_LEFT));
}
do {
auto found = std::ranges::search(curr_buffer, rec_delim);
if (found.begin() == curr_buffer.end()) {
buffer_end = true;
}
rec = mcc::utils::trimSpaces(std::string_view(curr_buffer.begin(), found.begin()), TrimType::TRIM_LEFT);
curr_buffer = {found.end(), curr_buffer.end()};
ec = parse_rec(rec);
} while (!buffer_end || !ec);
return ec;
}