mcc_keyvalue.h: fix for working with non-default constructible record
values, more smart 'set' operations for range values mcc_epoch.h: add constructors mcc_traits.h: add mcc_fixed_size_range and mcc_non_resizable_range concepts mcc_deserializer.h: fixes compilation issues for mcc_fixed_size_range and mcc_non_resizable_range ranges
This commit is contained in:
@@ -132,14 +132,17 @@ protected:
|
||||
|
||||
auto it = r.begin();
|
||||
for (auto const& el : r_str) {
|
||||
auto err = dsr(el, val, std::forward<DeserParamsT>(params)...);
|
||||
// auto err = dsr(el, val, std::forward<DeserParamsT>(params)...);
|
||||
auto err = dsr(el, val, params);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER);
|
||||
}
|
||||
|
||||
if (it == r.end()) {
|
||||
if constexpr (!traits::mcc_fixed_size_range<R>) {
|
||||
std::back_inserter(r) = val;
|
||||
it = r.end();
|
||||
}
|
||||
} else {
|
||||
*it = val;
|
||||
++it;
|
||||
|
||||
@@ -62,6 +62,26 @@ public:
|
||||
fromTimePoint(std::forward<decltype(other)>(other).UTC());
|
||||
}
|
||||
|
||||
MccCelestialCoordEpoch(traits::mcc_input_char_range auto&& str)
|
||||
{
|
||||
// ignore possible errors!!!
|
||||
fromCharRange(std::forward<decltype(str)>(str));
|
||||
}
|
||||
|
||||
template <typename ClockT, typename DurT>
|
||||
MccCelestialCoordEpoch(std::chrono::time_point<ClockT, DurT> const& tp) : MccCelestialCoordEpoch()
|
||||
{
|
||||
fromTimePoint(tp);
|
||||
}
|
||||
|
||||
template <typename VT>
|
||||
MccCelestialCoordEpoch(VT&& mjd)
|
||||
requires std::is_arithmetic_v<std::remove_cvref_t<VT>>
|
||||
{
|
||||
// ignore possible errors!!!
|
||||
fromMJD(std::forward<decltype(mjd)>(mjd));
|
||||
}
|
||||
|
||||
MccCelestialCoordEpoch& operator=(mcc_coord_epoch_c auto&& other)
|
||||
{
|
||||
fromTimePoint(std::forward<decltype(other)>(other).UTC());
|
||||
@@ -89,7 +109,7 @@ public:
|
||||
|
||||
template <typename VT>
|
||||
MccCelestialCoordEpoch& operator=(VT&& mjd)
|
||||
requires std::is_arithmetic_v<VT>
|
||||
requires std::is_arithmetic_v<std::remove_cvref_t<VT>>
|
||||
{
|
||||
// ignore possible errors!!!
|
||||
auto ok = fromMJD(std::forward<decltype(mjd)>(mjd));
|
||||
|
||||
@@ -176,6 +176,33 @@ public:
|
||||
template <typename T>
|
||||
std::expected<T, std::error_code> getValue(std::string_view key) const
|
||||
{
|
||||
// ugly, but works for non-default constructible values
|
||||
alignas(T) unsigned char buff[sizeof(T)];
|
||||
auto err = forKey(key, [&buff](auto const& rec) -> std::error_code {
|
||||
using VT = decltype(rec.value);
|
||||
if constexpr (std::constructible_from<T, VT>) {
|
||||
new (buff) T(rec.value);
|
||||
} else {
|
||||
return MccKeyValueHolderErrorCode::ERROR_INCOMPATIBLE_TYPE;
|
||||
}
|
||||
|
||||
return MccKeyValueHolderErrorCode::ERROR_OK;
|
||||
});
|
||||
|
||||
if (err) {
|
||||
return std::unexpected(err);
|
||||
} else {
|
||||
auto ptr = reinterpret_cast<T*>(&buff[0]);
|
||||
auto v = std::move(*ptr);
|
||||
ptr->~T(); // one needs explicitly call destructor here to avvoid side effects!!!
|
||||
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
// using VT = decltype(rec.value);
|
||||
@@ -195,16 +222,7 @@ public:
|
||||
// } else {
|
||||
// return v;
|
||||
// }
|
||||
|
||||
return forHash1(utils::FNV1aHash(key), [](auto const& rec) {
|
||||
using VT = decltype(rec.value);
|
||||
if constexpr (std::constructible_from<T, VT>) {
|
||||
return T{rec.value};
|
||||
} else {
|
||||
return std::unexpected(MccKeyValueHolderErrorCode::ERROR_INCOMPATIBLE_TYPE);
|
||||
}
|
||||
});
|
||||
}
|
||||
// }
|
||||
|
||||
template <std::ranges::contiguous_range R, typename T>
|
||||
std::error_code setValue(R const& key, const T& value)
|
||||
@@ -219,10 +237,40 @@ public:
|
||||
|
||||
auto ec = forHash(hash, [&value](auto& rec) -> std::error_code {
|
||||
using VT = decltype(rec.value);
|
||||
if constexpr (std::assignable_from<VT&, T>) {
|
||||
if constexpr (requires { rec.value = value; }) {
|
||||
rec.value = value;
|
||||
} else if constexpr (std::constructible_from<VT, T>) {
|
||||
rec.value = VT(value);
|
||||
} else if constexpr (std::ranges::range<VT> && std::ranges::range<T> &&
|
||||
requires(std::ranges::range_value_t<VT> v, std::ranges::range_value_t<T> t) {
|
||||
v = t;
|
||||
}) {
|
||||
const auto& val = std::is_pointer_v<std::decay_t<T>> ? std::span{value} : value;
|
||||
|
||||
size_t N = std::ranges::distance(rec.value.begin(), rec.value.end());
|
||||
size_t M = std::ranges::distance(val.begin(), val.end());
|
||||
|
||||
auto it = std::ranges::begin(rec.value);
|
||||
std::ranges::for_each_n(val.begin(), N > M ? M : N, [&it](auto const& el) {
|
||||
*it = el;
|
||||
++it;
|
||||
});
|
||||
|
||||
if (N >= M) { // resize to match the size of the input range
|
||||
if constexpr (!traits::mcc_non_resizable_range<VT>) {
|
||||
rec.value.resize(M);
|
||||
}
|
||||
} else { // append if allowed
|
||||
if constexpr (!traits::mcc_fixed_size_range<VT>) {
|
||||
std::ranges::for_each_n(val.begin(), N, [&it](auto const& el) {
|
||||
*it = el;
|
||||
++it;
|
||||
});
|
||||
|
||||
std::ranges::for_each(val | std::views::drop(N),
|
||||
[&rec](auto const& el) { std::back_inserter(rec.value) = el; });
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return MccKeyValueHolderErrorCode::ERROR_INCOMPATIBLE_TYPE;
|
||||
}
|
||||
@@ -450,67 +498,6 @@ 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)
|
||||
{
|
||||
|
||||
@@ -56,7 +56,13 @@ template <typename R>
|
||||
concept mcc_range_of_output_char_range =
|
||||
std::ranges::range<R> && traits::mcc_output_char_range<std::ranges::range_value_t<R>>;
|
||||
|
||||
// std::array, std::span(v_t, N), std::tuple
|
||||
template <typename R>
|
||||
concept mcc_fixed_size_range = std::ranges::range<R> && requires { std::tuple_size<std::remove_cvref_t<R>>::value; };
|
||||
|
||||
// non-resizable ranges
|
||||
template <typename R>
|
||||
concept mcc_non_resizable_range = std::ranges::range<R> && !requires(R r, std::size_t n) { r.resize(n); };
|
||||
|
||||
// https://stackoverflow.com/questions/72430369/how-to-check-that-a-type-is-formattable-using-type-traits-concepts)
|
||||
template <typename T>
|
||||
|
||||
@@ -4,6 +4,59 @@
|
||||
|
||||
using namespace mcc::impl;
|
||||
|
||||
|
||||
// example of non-default constructible class
|
||||
struct VT {
|
||||
VT(int v) : _v(v) {}
|
||||
|
||||
void set(int v)
|
||||
{
|
||||
_v = v;
|
||||
}
|
||||
|
||||
int v() const
|
||||
{
|
||||
return _v;
|
||||
}
|
||||
|
||||
protected:
|
||||
int _v{};
|
||||
};
|
||||
|
||||
|
||||
template <>
|
||||
struct mcc::impl::MccSerializer<VT> : MccSerializerBase {
|
||||
static constexpr std::string_view serializerName{"MCC-VT-SERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output,
|
||||
VT const& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
return MccSerializer<int>{}(output, value.v(), params);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct mcc::impl::MccDeserializer<VT> : MccDeserializerBase {
|
||||
static constexpr std::string_view deserializerName{"MCC-VT-DESERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input,
|
||||
VT& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
int v;
|
||||
auto err = MccDeserializer<int>{}(input, v, params);
|
||||
if (!err) {
|
||||
value.set(v);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static auto kv_desc = std::make_tuple(
|
||||
mcc_simple_kv_record_t{"bb", MccAngle{11.5_degs}, MccAngle{11.5_degs}, mcc_serialization_params_t{}},
|
||||
mcc_simple_kv_record_t{"aaa", std::string("AAA"), std::string("AAA"), mcc_serialization_params_t{}},
|
||||
@@ -12,7 +65,9 @@ static auto kv_desc = std::make_tuple(
|
||||
"ddd", MccAngle{11.5_degs}, MccAngle{11.5_degs},
|
||||
mcc_serialization_params_t{.angle_format = mcc::MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURS}},
|
||||
mcc_make_simple_kv_record("eee", 1.5),
|
||||
mcc_make_simple_kv_record("arr", std::vector<int>{1, 2, 3, 4, 5, 6, 7}));
|
||||
mcc_make_simple_kv_record("arr", std::vector<int>{1, 2, 3, 4, 5, 6, 7}),
|
||||
mcc_make_simple_kv_record("vt", VT(77)),
|
||||
mcc_make_simple_kv_record("sarr", std::array<double, 3>{1, 2, 3}));
|
||||
|
||||
|
||||
|
||||
@@ -88,6 +143,18 @@ int main()
|
||||
// return 1;
|
||||
}
|
||||
|
||||
err = kv.setValue("arr", std::array{10, 20, 30});
|
||||
if (err) {
|
||||
std::println("ERR = {}", err);
|
||||
// return 1;
|
||||
}
|
||||
|
||||
err = kv.setValue("sarr", std::vector{10, 20, 30, 40, 50});
|
||||
if (err) {
|
||||
std::println("ERR = {}", err);
|
||||
// return 1;
|
||||
}
|
||||
|
||||
std::println("------------------------------------");
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user