mcc_keyvalue.h: developing ...
This commit is contained in:
@@ -407,6 +407,5 @@ protected:
|
||||
|
||||
|
||||
static_assert(mcc_coord_epoch_c<MccCelestialCoordEpoch>, "!!!");
|
||||
|
||||
|
||||
static_assert(requires(MccCelestialCoordEpoch ep) { ep = std::chrono::system_clock::now(); });
|
||||
} // namespace mcc::impl
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
****************************************************************************************/
|
||||
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "mcc_constants.h"
|
||||
#include "mcc_deserializer.h"
|
||||
#include "mcc_serializer.h"
|
||||
@@ -19,7 +21,13 @@
|
||||
namespace mcc::impl
|
||||
{
|
||||
|
||||
enum class MccKeyValueHolderErrorCode : int { ERROR_OK, ERROR_INVALID_KEY, ERROR_INCOMPATIBLE_TYPE, ERROR_DESERIAL };
|
||||
enum class MccKeyValueHolderErrorCode : int {
|
||||
ERROR_OK,
|
||||
ERROR_INVALID_KEY,
|
||||
ERROR_INCOMPATIBLE_TYPE,
|
||||
ERROR_DESERIAL,
|
||||
ERROR_SERIAL
|
||||
};
|
||||
|
||||
} // namespace mcc::impl
|
||||
|
||||
@@ -59,6 +67,8 @@ struct MccKeyValueHolderCategory : public std::error_category {
|
||||
return "incompatible type";
|
||||
case MccKeyValueHolderErrorCode::ERROR_DESERIAL:
|
||||
return "deserialization error";
|
||||
case MccKeyValueHolderErrorCode::ERROR_SERIAL:
|
||||
return "serialization error";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
@@ -85,7 +95,7 @@ concept mcc_variant_valid_type_c = requires { !std::is_array_v<T> && !std::is_vo
|
||||
|
||||
template <typename T>
|
||||
concept mcc_keyvalue_record_c = requires(T t) {
|
||||
requires std::same_as<decltype(t.key), std::string_view>;
|
||||
requires std::same_as<decltype(t.key), const std::string_view>; // immutable key!!!
|
||||
requires mcc_variant_valid_type_c<decltype(t.value)>;
|
||||
};
|
||||
|
||||
@@ -133,6 +143,12 @@ public:
|
||||
}
|
||||
|
||||
|
||||
template <typename T, std::ranges::contiguous_range R>
|
||||
std::expected<T, std::error_code> getValue(R const& key) const
|
||||
{
|
||||
return getValue<T>(std::string_view{key});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::expected<T, std::error_code> getValue(std::string_view key) const
|
||||
{
|
||||
@@ -156,29 +172,59 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
template <std::ranges::contiguous_range R, typename T>
|
||||
std::error_code setValue(R const& key, const T& value)
|
||||
{
|
||||
return setValue<T>(std::string_view{key}, value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::error_code setValue(std::string_view key, const T& value)
|
||||
{
|
||||
return forKey(key, [value]<typename VT>(VT& val) -> std::error_code {
|
||||
if constexpr (std::convertible_to<T, VT>) {
|
||||
using r_t = std::invoke_result_t<decltype(std::chrono::system_clock::now)>;
|
||||
// static_assert(std::convertible_to<r_t, MccCelestialCoordEpoch>);
|
||||
// static_assert(std::assignable_from<MccCelestialCoordEpoch, r_t>);
|
||||
// static_assert(std::constructible_from<MccCelestialCoordEpoch, r_t>);
|
||||
// static_assert(std::destructible<MccCelestialCoordEpoch>);
|
||||
|
||||
return forKey(key, [value, key]<typename VT>(VT& val) -> std::error_code {
|
||||
if constexpr (requires(std::decay_t<VT> v) { v = value; }) {
|
||||
val = value;
|
||||
} else if constexpr (std::constructible_from<VT, T>) {
|
||||
val = VT(value);
|
||||
} else {
|
||||
return MccKeyValueHolderErrorCode::ERROR_INCOMPATIBLE_TYPE;
|
||||
}
|
||||
std::println("FORKEY_FUN: {} = {}", key, value);
|
||||
// if constexpr (std::convertible_to<T, VT>) {
|
||||
// val = value;
|
||||
// } else if constexpr (std::constructible_from<VT, T>) {
|
||||
// val = VT(value);
|
||||
// } else if constexpr (std::assignable_from<VT, T>) {
|
||||
// val = value;
|
||||
// } else {
|
||||
// return MccKeyValueHolderErrorCode::ERROR_INCOMPATIBLE_TYPE;
|
||||
// }
|
||||
|
||||
return MccKeyValueHolderErrorCode::ERROR_OK;
|
||||
// if constexpr (std::convertible_to<T, VT>) {
|
||||
// val = value;
|
||||
// } else if constexpr (std::constructible_from<VT, T>) {
|
||||
// val = VT(value);
|
||||
// } else if constexpr (std::assignable_from<VT, T>) {
|
||||
// val = value;
|
||||
// } else {
|
||||
// return MccKeyValueHolderErrorCode::ERROR_INCOMPATIBLE_TYPE;
|
||||
// }
|
||||
|
||||
// return MccKeyValueHolderErrorCode::ERROR_OK;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
template <std::ranges::contiguous_range R,
|
||||
std::ranges::input_range RecDelimT = std::string_view,
|
||||
template <traits::mcc_input_char_range R,
|
||||
traits::mcc_input_char_range RecDelimT = std::string_view,
|
||||
mcc_serialization_params_c SerParamsT = mcc_serialization_params_t>
|
||||
std::error_code fromCharRange(const R& buffer,
|
||||
RecDelimT rec_delim = std::string_view("\n"),
|
||||
RecDelimT rec_delim = std::string_view("\n"), // records delimiter
|
||||
SerParamsT const& ser_params = mcc_serialization_params_t{})
|
||||
requires std::ranges::contiguous_range<R>
|
||||
{
|
||||
if constexpr (std::is_array_v<std::decay_t<R>>) { // char*, const char*
|
||||
if constexpr (std::is_array_v<std::decay_t<RecDelimT>>) {
|
||||
@@ -193,50 +239,134 @@ public:
|
||||
}
|
||||
|
||||
std::error_code ec{};
|
||||
std::string_view rec, key, value;
|
||||
|
||||
std::string_view rec, key, value, inline_comm;
|
||||
std::vector<std::string> head_comm;
|
||||
size_t key_hash;
|
||||
|
||||
auto recs = std::views::split(buffer, std::move(rec_delim));
|
||||
|
||||
for (auto const& el : recs) {
|
||||
rec = mcc::utils::trimSpaces(el, utils::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
|
||||
if (found.begin() != rec.end()) { // there was the comment sequence in record
|
||||
if (found.begin() != rec.begin()) { // inline comment
|
||||
inline_comm =
|
||||
std::string_view{found.begin() + COMMENT_SEQ.size(), rec.end()}; // mark inline comment
|
||||
} else { // head comment
|
||||
head_comm.push_back({found.end(), rec.end()});
|
||||
std::println("COMM: <{}>", head_comm.back());
|
||||
}
|
||||
|
||||
rec = std::string_view(rec.begin(), found.begin());
|
||||
}
|
||||
|
||||
if (rec.size()) {
|
||||
found = std::ranges::search(rec, KEY_VALUE_DELIM);
|
||||
if (found.begin() != rec.begin()) { // ignore an empty key
|
||||
if (found.begin() != rec.begin()) {
|
||||
key = trimSpaces(std::string_view(rec.begin(), found.begin()), utils::TrimType::TRIM_RIGHT);
|
||||
value = std::string_view(found.end(), rec.end());
|
||||
|
||||
ec = forKey(key, [value, &ser_params]<typename VT>(VT& v) {
|
||||
auto err = MccDeserializer<VT>(value, v, ser_params);
|
||||
key_hash = utils::FNV1aHash(key);
|
||||
|
||||
// ec = forKey(key, [value, &ser_params]<typename VT>(VT& v) {
|
||||
// auto err = MccDeserializer<VT>{}(value, v, ser_params);
|
||||
// if (err) {
|
||||
// return MccKeyValueHolderErrorCode::ERROR_DESERIAL;
|
||||
// }
|
||||
|
||||
// return MccKeyValueHolderErrorCode::ERROR_OK;
|
||||
// });
|
||||
|
||||
ec = forHash(key_hash, [value, &ser_params]<typename VT>(VT& v) {
|
||||
auto err = MccDeserializer<VT>{}(value, v, ser_params);
|
||||
if (err) {
|
||||
return MccKeyValueHolderErrorCode::ERROR_DESERIAL;
|
||||
}
|
||||
|
||||
return MccKeyValueHolderErrorCode::ERROR_OK;
|
||||
});
|
||||
|
||||
if (ec) { // exit in the case of error
|
||||
break;
|
||||
}
|
||||
|
||||
// save head comment
|
||||
_headComment[key_hash] = head_comm;
|
||||
head_comm.clear();
|
||||
_inlineComment[key_hash] = inline_comm;
|
||||
} else { // an empty key
|
||||
ec = MccKeyValueHolderErrorCode::ERROR_INVALID_KEY;
|
||||
break;
|
||||
}
|
||||
} // just comment string starting from the beginning, just skip it (no error)
|
||||
|
||||
} // empty record, just skip it (no error)
|
||||
|
||||
if (ec) {
|
||||
break;
|
||||
} else { // empty record, just skip it (no error)
|
||||
head_comm.push_back({el.begin(), el.end()});
|
||||
std::println("EMPTY COMM: <{}>", head_comm.back());
|
||||
}
|
||||
}
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
template <traits::mcc_output_char_range R,
|
||||
traits::mcc_input_char_range RecDelimT = std::string_view,
|
||||
mcc_serialization_params_c SerParamsT = mcc_serialization_params_t>
|
||||
std::error_code toCharRange(R& output_buffer,
|
||||
RecDelimT rec_delim = std::string_view{"\n"},
|
||||
SerParamsT const& ser_params = mcc_serialization_params_t{})
|
||||
{
|
||||
std::error_code ec{};
|
||||
|
||||
auto write_rec = [&output_buffer, &rec_delim, &ec, &ser_params, this]<size_t I>() {
|
||||
auto key = std::get<I>(_keyValue).key;
|
||||
auto val = std::get<I>(_keyValue).value;
|
||||
using val_t = std::remove_cvref_t<decltype(val)>;
|
||||
|
||||
std::string buff;
|
||||
auto err = MccSerializer<val_t>{}(buff, val, ser_params);
|
||||
if (err) {
|
||||
ec = MccKeyValueHolderErrorCode::ERROR_SERIAL;
|
||||
} else {
|
||||
size_t hash = _hashes[I];
|
||||
// write head comment
|
||||
if (_headComment[hash].size()) {
|
||||
for (auto const& comm : _headComment[hash]) {
|
||||
// if (comm.size()) {
|
||||
std::format_to(std::back_inserter(output_buffer), "{}{}", COMM_SEQ, comm);
|
||||
// }
|
||||
std::ranges::copy(rec_delim, std::back_inserter(output_buffer));
|
||||
}
|
||||
}
|
||||
|
||||
// key and value
|
||||
std::format_to(std::back_inserter(output_buffer), "{}{}{}{}", rec_delim, key, KEY_VALUE_DELIM, buff);
|
||||
|
||||
// inline comment
|
||||
if (_inlineComment[hash].size()) {
|
||||
std::format_to(std::back_inserter(output_buffer), " {}{}", COMMENT_SEQ, _inlineComment[hash]);
|
||||
}
|
||||
|
||||
// record delimiter
|
||||
std::ranges::copy(rec_delim, std::back_inserter(output_buffer));
|
||||
}
|
||||
};
|
||||
|
||||
[&write_rec]<size_t... Is>(std::index_sequence<Is...>) {
|
||||
(write_rec.template operator()<Is>(), ...);
|
||||
}(std::make_index_sequence<std::tuple_size_v<DESCR_T>>());
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
protected:
|
||||
DESCR_T _keyValue;
|
||||
|
||||
std::array<size_t, std::tuple_size_v<DESCR_T>> _hashes;
|
||||
std::array<size_t, std::tuple_size_v<DESCR_T>> _hashes; // key hashes
|
||||
std::unordered_map<size_t, std::vector<std::string>> _headComment; // comment string/strings before key
|
||||
std::unordered_map<size_t, std::string> _inlineComment; // inline (after key=value pair) comment
|
||||
|
||||
//
|
||||
// NOTE: deduced this is needed here to use "forKey" method in getter and setter (const and non-const contexts)!!!
|
||||
@@ -266,5 +396,10 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
template <mcc_variant_valid_type_c T>
|
||||
struct mcc_simple_kv_record_t {
|
||||
const std::string_view key;
|
||||
T value;
|
||||
};
|
||||
|
||||
} // namespace mcc::impl
|
||||
Reference in New Issue
Block a user