...
This commit is contained in:
102
mcc/mcc_utils.h
102
mcc/mcc_utils.h
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user