Compare commits
23 Commits
af0268218a
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| cd97ed875f | |||
| b3c7584205 | |||
| 5984bc5204 | |||
| d865e51ffb | |||
| 6e6f230f4d | |||
| a1f17f0d76 | |||
| e1a136a839 | |||
| 3497850e1f | |||
| e9c329d88f | |||
| 445a029a2f | |||
| 8e5e3631ba | |||
| 304464dbda | |||
| 4b5a390987 | |||
| 47ba7342e7 | |||
| c5f17b7403 | |||
| 8d36444c51 | |||
| d40ecb5df7 | |||
| d8130cede2 | |||
| 056c152d49 | |||
|
|
9630751a4d | ||
| 3dbe4c12b7 | |||
| 537207cd16 | |||
| f314c6a2c5 |
@@ -253,6 +253,7 @@ set(MCC_SRC
|
||||
include/mcc/mcc_deserializer.h
|
||||
include/mcc/mcc_serializer.h
|
||||
include/mcc/mcc_generic_mount.h
|
||||
include/mcc/mcc_keyvalue.h
|
||||
)
|
||||
|
||||
if(USE_SPDLOG)
|
||||
@@ -354,6 +355,9 @@ if(BUILD_TESTS)
|
||||
|
||||
add_executable(mcc_pcm_z1000_test tests/mcc_pcm_z1000_test.cpp)
|
||||
target_link_libraries(mcc_pcm_z1000_test PRIVATE ${PROJECT_NAME})
|
||||
|
||||
add_executable(mcc_keyvalue_test tests/mcc_keyvalue_test.cpp)
|
||||
target_link_libraries(mcc_keyvalue_test PRIVATE ${PROJECT_NAME})
|
||||
else()
|
||||
# This is just a stub to allow access to the path and library settings for the ${PROJECT_NAME} target during development
|
||||
add_executable(just_stub EXCLUDE_FROM_ALL main.cpp)
|
||||
|
||||
@@ -21,8 +21,8 @@ include(FortranCInterface)
|
||||
FortranCInterface_HEADER(
|
||||
FortranCInterface.h
|
||||
MACRO_NAMESPACE "FC_"
|
||||
# SYMBOL_NAMESPACE "fp_"
|
||||
SYMBOL_NAMESPACE ""
|
||||
SYMBOL_NAMESPACE "fitpack_"
|
||||
#SYMBOL_NAMESPACE ""
|
||||
# SYMBOLS ${func_str}
|
||||
SYMBOLS ${func_name}
|
||||
)
|
||||
|
||||
@@ -8,139 +8,147 @@
|
||||
|
||||
extern "C" {
|
||||
|
||||
|
||||
|
||||
/* fitting on XY-grid */
|
||||
void surfit(int* iopt,
|
||||
int* m,
|
||||
double* x,
|
||||
double* y,
|
||||
double* z,
|
||||
double* w,
|
||||
double* xb,
|
||||
double* xe,
|
||||
double* yb,
|
||||
double* ye,
|
||||
int* kx,
|
||||
int* ky,
|
||||
double* s,
|
||||
int* nxest,
|
||||
int* nyest,
|
||||
int* nmax,
|
||||
double* eps,
|
||||
int* nx,
|
||||
double* tx,
|
||||
int* ny,
|
||||
double* ty,
|
||||
double* c,
|
||||
double* fp,
|
||||
double* wrk1,
|
||||
int* lwrk1,
|
||||
double* wrk2,
|
||||
int* lwrk2,
|
||||
int* iwrk,
|
||||
int* kwrk,
|
||||
int* ier);
|
||||
void fitpack_surfit(int* iopt,
|
||||
// void surfit(int* iopt,
|
||||
int* m,
|
||||
double* x,
|
||||
double* y,
|
||||
double* z,
|
||||
double* w,
|
||||
double* xb,
|
||||
double* xe,
|
||||
double* yb,
|
||||
double* ye,
|
||||
int* kx,
|
||||
int* ky,
|
||||
double* s,
|
||||
int* nxest,
|
||||
int* nyest,
|
||||
int* nmax,
|
||||
double* eps,
|
||||
int* nx,
|
||||
double* tx,
|
||||
int* ny,
|
||||
double* ty,
|
||||
double* c,
|
||||
double* fp,
|
||||
double* wrk1,
|
||||
int* lwrk1,
|
||||
double* wrk2,
|
||||
int* lwrk2,
|
||||
int* iwrk,
|
||||
int* kwrk,
|
||||
int* ier);
|
||||
|
||||
/* XY-grid */
|
||||
void bispev(double* tx,
|
||||
int* nx,
|
||||
double* ty,
|
||||
int* ny,
|
||||
double* c,
|
||||
int* kx,
|
||||
int* ky,
|
||||
double* x,
|
||||
int* mx,
|
||||
double* y,
|
||||
int* my,
|
||||
double* z,
|
||||
double* wrk,
|
||||
int* lwrk,
|
||||
int* iwrk,
|
||||
int* kwrk,
|
||||
int* ier);
|
||||
void fitpack_bispev(double* tx,
|
||||
// void bispev(double* tx,
|
||||
int* nx,
|
||||
double* ty,
|
||||
int* ny,
|
||||
double* c,
|
||||
int* kx,
|
||||
int* ky,
|
||||
double* x,
|
||||
int* mx,
|
||||
double* y,
|
||||
int* my,
|
||||
double* z,
|
||||
double* wrk,
|
||||
int* lwrk,
|
||||
int* iwrk,
|
||||
int* kwrk,
|
||||
int* ier);
|
||||
|
||||
/* XY-grid */
|
||||
void parder(double* tx,
|
||||
int* nx,
|
||||
double* ty,
|
||||
int* ny,
|
||||
double* c,
|
||||
int* kx,
|
||||
int* ky,
|
||||
int* nux,
|
||||
int* nuy,
|
||||
double* x,
|
||||
int* mx,
|
||||
double* y,
|
||||
int* my,
|
||||
double* z,
|
||||
double* wrk,
|
||||
int* lwrk,
|
||||
int* iwrk,
|
||||
int* kwrk,
|
||||
int* ier);
|
||||
void fitpack_parder(double* tx,
|
||||
// void parder(double* tx,
|
||||
int* nx,
|
||||
double* ty,
|
||||
int* ny,
|
||||
double* c,
|
||||
int* kx,
|
||||
int* ky,
|
||||
int* nux,
|
||||
int* nuy,
|
||||
double* x,
|
||||
int* mx,
|
||||
double* y,
|
||||
int* my,
|
||||
double* z,
|
||||
double* wrk,
|
||||
int* lwrk,
|
||||
int* iwrk,
|
||||
int* kwrk,
|
||||
int* ier);
|
||||
|
||||
/* fitting on sphere */
|
||||
void sphere(int* iopt,
|
||||
int* m,
|
||||
double* teta,
|
||||
double* phi,
|
||||
double* r,
|
||||
double* w,
|
||||
double* s,
|
||||
int* ntest,
|
||||
int* npest,
|
||||
double* eps,
|
||||
int* nt,
|
||||
double* tt,
|
||||
int* np,
|
||||
double* tp,
|
||||
double* c,
|
||||
double* fp,
|
||||
double* wrk1,
|
||||
int* lwrk1,
|
||||
double* wrk2,
|
||||
int* lwrk2,
|
||||
int* iwrk,
|
||||
int* kwrk,
|
||||
int* ier);
|
||||
void fitpack_sphere(int* iopt,
|
||||
// void sphere(int* iopt,
|
||||
int* m,
|
||||
double* teta,
|
||||
double* phi,
|
||||
double* r,
|
||||
double* w,
|
||||
double* s,
|
||||
int* ntest,
|
||||
int* npest,
|
||||
double* eps,
|
||||
int* nt,
|
||||
double* tt,
|
||||
int* np,
|
||||
double* tp,
|
||||
double* c,
|
||||
double* fp,
|
||||
double* wrk1,
|
||||
int* lwrk1,
|
||||
double* wrk2,
|
||||
int* lwrk2,
|
||||
int* iwrk,
|
||||
int* kwrk,
|
||||
int* ier);
|
||||
|
||||
/* calculation for set of points (not grid) */
|
||||
void bispeu(double* tx,
|
||||
int* nx,
|
||||
double* ty,
|
||||
int* ny,
|
||||
double* c,
|
||||
int* kx,
|
||||
int* ky,
|
||||
double* x,
|
||||
double* y,
|
||||
double* z,
|
||||
int* m,
|
||||
double* wrk,
|
||||
int* lwrk,
|
||||
int* ier);
|
||||
void fitpack_bispeu(double* tx,
|
||||
// void bispeu(double* tx,
|
||||
int* nx,
|
||||
double* ty,
|
||||
int* ny,
|
||||
double* c,
|
||||
int* kx,
|
||||
int* ky,
|
||||
double* x,
|
||||
double* y,
|
||||
double* z,
|
||||
int* m,
|
||||
double* wrk,
|
||||
int* lwrk,
|
||||
int* ier);
|
||||
|
||||
|
||||
/* calculation for set of points (not grid) */
|
||||
void pardeu(double* tx,
|
||||
int* nx,
|
||||
double* ty,
|
||||
int* ny,
|
||||
double* c,
|
||||
int* kx,
|
||||
int* ky,
|
||||
int* nux,
|
||||
int* nuy,
|
||||
double* x,
|
||||
double* y,
|
||||
double* z,
|
||||
int* m,
|
||||
double* wrk,
|
||||
int* lwrk,
|
||||
int* iwrk,
|
||||
int* kwrk,
|
||||
int* ier);
|
||||
void fitpack_pardeu(double* tx,
|
||||
// void pardeu(double* tx,
|
||||
int* nx,
|
||||
double* ty,
|
||||
int* ny,
|
||||
double* c,
|
||||
int* kx,
|
||||
int* ky,
|
||||
int* nux,
|
||||
int* nuy,
|
||||
double* x,
|
||||
double* y,
|
||||
double* z,
|
||||
int* m,
|
||||
double* wrk,
|
||||
int* lwrk,
|
||||
int* iwrk,
|
||||
int* kwrk,
|
||||
int* ier);
|
||||
}
|
||||
|
||||
|
||||
@@ -257,23 +265,15 @@ int fitpack_sphere_smooth(const TethaT& tetha,
|
||||
if constexpr (std::ranges::contiguous_range<WeightT>) {
|
||||
auto weight_ptr = const_cast<double*>(std::ranges::data(weight));
|
||||
|
||||
sphere(&iopt, &m, tetha_ptr, phi_ptr, func_ptr, weight_ptr, &s_par, &nt, &np, &eps, &ntest, tetha_knots_ptr,
|
||||
&npest, phi_knots_ptr, std::ranges::data(coeffs), &resi2_sum, wrk1.data(), &lwrk1, wrk2.data(), &lwrk2,
|
||||
iwrk.data(), &kwrk, &res);
|
||||
// sphere(&iopt, &m, std::ranges::data(tetha), std::ranges::data(phi), std::ranges::data(func),
|
||||
// std::ranges::data(weight), &s_par, &ntest, &npest, &eps, &ntest, std::ranges::data(tetha_knots),
|
||||
// &npest, std::ranges::data(phi_knots), std::ranges::data(coeffs), &resi2_sum, wrk1.data(), &lwrk1,
|
||||
// wrk2.data(), &lwrk2, iwrk.data(), &kwrk, &res);
|
||||
fitpack_sphere(&iopt, &m, tetha_ptr, phi_ptr, func_ptr, weight_ptr, &s_par, &nt, &np, &eps, &ntest,
|
||||
tetha_knots_ptr, &npest, phi_knots_ptr, std::ranges::data(coeffs), &resi2_sum, wrk1.data(),
|
||||
&lwrk1, wrk2.data(), &lwrk2, iwrk.data(), &kwrk, &res);
|
||||
} else {
|
||||
std::vector<double> weight_vec(m, weight);
|
||||
|
||||
sphere(&iopt, &m, tetha_ptr, phi_ptr, func_ptr, weight_vec.data(), &s_par, &nt, &np, &eps, &ntest,
|
||||
tetha_knots_ptr, &npest, phi_knots_ptr, std::ranges::data(coeffs), &resi2_sum, wrk1.data(), &lwrk1,
|
||||
wrk2.data(), &lwrk2, iwrk.data(), &kwrk, &res);
|
||||
// res = sphere(&iopt, &m, std::ranges::data(tetha), std::ranges::data(phi), std::ranges::data(func),
|
||||
// weight_vec.data(), &s_par, &ntest, &npest, &eps, &ntest, std::ranges::data(tetha_knots), &npest,
|
||||
// std::ranges::data(phi_knots), std::ranges::data(coeffs), &resi2_sum, wrk1.get(), &lwrk1,
|
||||
// wrk2.get(), &lwrk2, iwrk.get(), &kwrk, &res);
|
||||
fitpack_sphere(&iopt, &m, tetha_ptr, phi_ptr, func_ptr, weight_vec.data(), &s_par, &nt, &np, &eps, &ntest,
|
||||
tetha_knots_ptr, &npest, phi_knots_ptr, std::ranges::data(coeffs), &resi2_sum, wrk1.data(),
|
||||
&lwrk1, wrk2.data(), &lwrk2, iwrk.data(), &kwrk, &res);
|
||||
}
|
||||
|
||||
|
||||
@@ -367,8 +367,8 @@ int fitpack_eval_spl2d_grid(const TXT& tx,
|
||||
auto x_ptr = const_cast<double*>(std::ranges::data(x));
|
||||
auto y_ptr = const_cast<double*>(std::ranges::data(y));
|
||||
|
||||
bispev(tx_ptr, &ntx, ty_ptr, &nty, coeffs_ptr, &kx, &ky, x_ptr, &mx, y_ptr, &my, std::ranges::data(func),
|
||||
wrk.data(), &lwrk, iwrk.data(), &kwrk, &ier);
|
||||
fitpack_bispev(tx_ptr, &ntx, ty_ptr, &nty, coeffs_ptr, &kx, &ky, x_ptr, &mx, y_ptr, &my, std::ranges::data(func),
|
||||
wrk.data(), &lwrk, iwrk.data(), &kwrk, &ier);
|
||||
|
||||
return ier;
|
||||
}
|
||||
@@ -431,8 +431,10 @@ int fitpack_eval_spl2d(const TXT& tx,
|
||||
int lwrk = kx + ky + 2;
|
||||
std::vector<double> wrk(lwrk);
|
||||
|
||||
bispeu(tx_ptr, &ntx, ty_ptr, &nty, coeffs_ptr, &kx, &ky, x_ptr, y_ptr, std::ranges::data(func), &m, wrk.data(),
|
||||
&lwrk, &ier);
|
||||
fitpack_bispeu(tx_ptr, &ntx, ty_ptr, &nty, coeffs_ptr, &kx, &ky, x_ptr, y_ptr, std::ranges::data(func), &m,
|
||||
wrk.data(), &lwrk, &ier);
|
||||
// bispeu(tx_ptr, &ntx, ty_ptr, &nty, coeffs_ptr, &kx, &ky, x_ptr, y_ptr, std::ranges::data(func), &m, wrk.data(),
|
||||
// &lwrk, &ier);
|
||||
|
||||
return ier;
|
||||
}
|
||||
@@ -536,8 +538,8 @@ int fitpack_parder_spl2d_grid(const TXT& tx,
|
||||
|
||||
int ier = 0;
|
||||
|
||||
parder(tx_ptr, &ntx, ty_ptr, &nty, coeffs_ptr, &kx, &ky, &dx, &dy, x_ptr, &mx, y_ptr, &my, std::ranges::data(pder),
|
||||
wrk.data(), &lwrk, iwrk.data(), &kwrk, &ier);
|
||||
fitpack_parder(tx_ptr, &ntx, ty_ptr, &nty, coeffs_ptr, &kx, &ky, &dx, &dy, x_ptr, &mx, y_ptr, &my,
|
||||
std::ranges::data(pder), wrk.data(), &lwrk, iwrk.data(), &kwrk, &ier);
|
||||
|
||||
return ier;
|
||||
}
|
||||
@@ -604,8 +606,8 @@ int fitpack_parder_spl2d(const TXT& tx,
|
||||
int kwrk = 2 * m;
|
||||
std::vector<int> iwrk(kwrk);
|
||||
|
||||
pardeu(tx_ptr, &ntx, ty_ptr, &nty, coeffs_ptr, &kx, &ky, &dx, &dy, x_ptr, y_ptr, std::ranges::data(pder), &m,
|
||||
wrk.data(), &lwrk, iwrk.data(), &kwrk, &ier);
|
||||
fitpack_pardeu(tx_ptr, &ntx, ty_ptr, &nty, coeffs_ptr, &kx, &ky, &dx, &dy, x_ptr, y_ptr, std::ranges::data(pder),
|
||||
&m, wrk.data(), &lwrk, iwrk.data(), &kwrk, &ier);
|
||||
|
||||
return ier;
|
||||
}
|
||||
@@ -645,5 +647,4 @@ int fitpack_parder_spl2d(const TXT& tx,
|
||||
return fitpack_parder_spl2d(tx, ty, coeffs, xv, yv, pv, dx, dy, kx, ky);
|
||||
}
|
||||
|
||||
|
||||
} // namespace mcc::bsplines
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -126,19 +126,23 @@ protected:
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
|
||||
auto r_str = std::views::split(input, params.seq_delim);
|
||||
// auto r_str = std::views::split(input, params.seq_delim);
|
||||
auto r_str = std::views::split(input, params.elem_delim);
|
||||
VT val;
|
||||
|
||||
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()) {
|
||||
std::back_inserter(r) = val;
|
||||
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());
|
||||
@@ -79,17 +99,17 @@ public:
|
||||
|
||||
|
||||
template <typename ClockT, typename DurT>
|
||||
MccCelestialCoordEpoch& operator=(std::chrono::time_point<ClockT, DurT>&& tp)
|
||||
MccCelestialCoordEpoch& operator=(std::chrono::time_point<ClockT, DurT> const& tp)
|
||||
{
|
||||
// ignore possible errors!!!
|
||||
auto ok = fromTimePoint(std::forward<decltype(tp)>(tp));
|
||||
auto ok = fromTimePoint(tp);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
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));
|
||||
@@ -139,17 +159,17 @@ public:
|
||||
}
|
||||
|
||||
template <typename ClockT, typename DurT>
|
||||
bool fromTimePoint(std::chrono::time_point<ClockT, DurT>&& tp)
|
||||
bool fromTimePoint(std::chrono::time_point<ClockT, DurT> const& tp)
|
||||
{
|
||||
if constexpr (std::same_as<ClockT, std::chrono::system_clock>) {
|
||||
_UTC = std::chrono::time_point_cast<decltype(_UTC)::duration>(std::forward<decltype(tp)>(tp));
|
||||
_UTC = std::chrono::time_point_cast<decltype(_UTC)::duration>(tp);
|
||||
} else if constexpr (std::same_as<ClockT, std::chrono::utc_clock>) {
|
||||
auto stp = std::chrono::utc_clock::to_sys(std::forward<decltype(tp)>(tp));
|
||||
_UTC = std::chrono::time_point_cast<decltype(_UTC)::duration>(std::forward<decltype(tp)>(stp));
|
||||
auto stp = std::chrono::utc_clock::to_sys(tp);
|
||||
_UTC = std::chrono::time_point_cast<decltype(_UTC)::duration>(stp);
|
||||
} else if constexpr (std::same_as<ClockT, std::chrono::tai_clock>) {
|
||||
return fromTimePoint(ClockT::to_utc(std::forward<decltype(tp)>(tp)));
|
||||
return fromTimePoint(ClockT::to_utc(tp));
|
||||
} else if constexpr (std::same_as<ClockT, std::chrono::gps_clock>) {
|
||||
return fromTimePoint(ClockT::to_utc(std::forward<decltype(tp)>(tp)));
|
||||
return fromTimePoint(ClockT::to_utc(tp));
|
||||
} else {
|
||||
static_assert(false, "UNSUPPORTED CLOCK!!!");
|
||||
}
|
||||
@@ -407,6 +427,5 @@ protected:
|
||||
|
||||
|
||||
static_assert(mcc_coord_epoch_c<MccCelestialCoordEpoch>, "!!!");
|
||||
|
||||
|
||||
static_assert(requires(MccCelestialCoordEpoch ep) { ep = std::chrono::system_clock::now(); });
|
||||
} // namespace mcc::impl
|
||||
|
||||
615
include/mcc/mcc_keyvalue.h
Normal file
615
include/mcc/mcc_keyvalue.h
Normal file
@@ -0,0 +1,615 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
/****************************************************************************************
|
||||
* *
|
||||
* MOUNT CONTROL COMPONENTS LIBRARY *
|
||||
* *
|
||||
* *
|
||||
* IMPLEMENTATION OF KEY-VALUE PAIRS HOLDER *
|
||||
* *
|
||||
****************************************************************************************/
|
||||
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "mcc_deserializer.h"
|
||||
#include "mcc_serializer.h"
|
||||
#include "mcc_utils.h"
|
||||
|
||||
namespace mcc::impl
|
||||
{
|
||||
|
||||
enum class MccKeyValueHolderErrorCode : int {
|
||||
ERROR_OK,
|
||||
ERROR_INVALID_KEY,
|
||||
ERROR_INCOMPATIBLE_TYPE,
|
||||
ERROR_DESERIAL,
|
||||
ERROR_SERIAL
|
||||
};
|
||||
|
||||
} // namespace mcc::impl
|
||||
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template <>
|
||||
class is_error_code_enum<mcc::impl::MccKeyValueHolderErrorCode> : public true_type
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace mcc::impl
|
||||
{
|
||||
|
||||
// error category
|
||||
struct MccKeyValueHolderCategory : public std::error_category {
|
||||
MccKeyValueHolderCategory() : std::error_category() {}
|
||||
|
||||
const char* name() const noexcept override
|
||||
{
|
||||
return "MCC-KEYVALUEHOLDER-ERR-CATEGORY";
|
||||
}
|
||||
|
||||
std::string message(int ec) const override
|
||||
{
|
||||
MccKeyValueHolderErrorCode err = static_cast<MccKeyValueHolderErrorCode>(ec);
|
||||
|
||||
switch (err) {
|
||||
case MccKeyValueHolderErrorCode::ERROR_OK:
|
||||
return "OK";
|
||||
case MccKeyValueHolderErrorCode::ERROR_INVALID_KEY:
|
||||
return "invalid key value";
|
||||
case MccKeyValueHolderErrorCode::ERROR_INCOMPATIBLE_TYPE:
|
||||
return "incompatible type";
|
||||
case MccKeyValueHolderErrorCode::ERROR_DESERIAL:
|
||||
return "deserialization error";
|
||||
case MccKeyValueHolderErrorCode::ERROR_SERIAL:
|
||||
return "serialization error";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static const MccKeyValueHolderCategory& get()
|
||||
{
|
||||
static const MccKeyValueHolderCategory constInst;
|
||||
return constInst;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
inline std::error_code make_error_code(MccKeyValueHolderErrorCode ec)
|
||||
{
|
||||
return std::error_code(static_cast<int>(ec), MccKeyValueHolderCategory::get());
|
||||
}
|
||||
|
||||
|
||||
// to follow std::variant requirements (not references, not array, not void)
|
||||
template <typename T>
|
||||
concept mcc_record_value_c = requires { !std::is_array_v<T> && !std::is_void_v<T> && !std::is_reference_v<T>; };
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept mcc_keyvalue_record_c = requires(T t) {
|
||||
requires std::same_as<decltype(t.key), const std::string_view>; // key name is immutable!!!
|
||||
requires mcc_record_value_c<decltype(t.value)>; // value is mutable
|
||||
requires mcc_record_value_c<decltype(t.default_value)>; // default value is mutable
|
||||
requires mcc_serialization_params_c<decltype(t.serial_pars)>; // serialization parameters
|
||||
};
|
||||
|
||||
|
||||
// must be a std::tuple of mcc_keyvalue_record_c
|
||||
template <typename T>
|
||||
concept mcc_keyvalue_desc_c = requires(T t) { []<mcc_keyvalue_record_c... Ts>(std::tuple<Ts...>) {}(t); };
|
||||
|
||||
|
||||
// use of 'inline' here to avoid '-Wsubobject-linkage' GCC-warning
|
||||
inline constexpr char MCC_KV_COMMENT_SEQ_ARR[] = "#";
|
||||
inline constexpr char MCC_KV_KEY_VALUE_DELIM_SEQ_ARR[] = "=";
|
||||
inline constexpr char MCC_KV_COMPOSITE_VALUE_DELIM_SEQ_ARR[] = ",";
|
||||
|
||||
|
||||
template <mcc_keyvalue_desc_c DESCR_T,
|
||||
const char* COMM_SEQ = MCC_KV_COMMENT_SEQ_ARR, // comment char sequence
|
||||
const char* KV_DELIM = MCC_KV_KEY_VALUE_DELIM_SEQ_ARR // key-value delimiter
|
||||
>
|
||||
class MccKeyValueHolder
|
||||
{
|
||||
public:
|
||||
enum OutputPolicy {
|
||||
OPOLICY_CHANGED_ONLY, // serialize only changed and previously deserialized (by fromCharRange method) key-value
|
||||
// pairs
|
||||
OPOLICY_FULL // serialize entire set of key-value pairs
|
||||
};
|
||||
|
||||
static constexpr std::string_view DEFAULT_RECORD_DELIMITER{"\n"};
|
||||
|
||||
static constexpr std::string_view COMMENT_SEQ{COMM_SEQ == nullptr ? MCC_KV_COMMENT_SEQ_ARR
|
||||
: COMM_SEQ[0] == '\0' ? MCC_KV_COMMENT_SEQ_ARR
|
||||
: COMM_SEQ};
|
||||
|
||||
static constexpr std::string_view KEY_VALUE_DELIM{KV_DELIM == nullptr ? MCC_KV_KEY_VALUE_DELIM_SEQ_ARR
|
||||
: KV_DELIM[0] == '\0' ? MCC_KV_KEY_VALUE_DELIM_SEQ_ARR
|
||||
: KV_DELIM};
|
||||
|
||||
static constexpr size_t NUMBER_OF_RECORDS = std::tuple_size_v<DESCR_T>;
|
||||
|
||||
MccKeyValueHolder(DESCR_T desc) : _keyValue(desc)
|
||||
{
|
||||
[this]<size_t... I>(std::index_sequence<I...>) {
|
||||
((_hashes[I] = utils::FNV1aHash(std::get<I>(_keyValue).key)), ...);
|
||||
}(std::make_index_sequence<NUMBER_OF_RECORDS>());
|
||||
|
||||
_changedKey.insert_range(_hashes);
|
||||
}
|
||||
|
||||
MccKeyValueHolder(MccKeyValueHolder const& other) : MccKeyValueHolder(other._keyValue)
|
||||
{
|
||||
copyInst(other);
|
||||
};
|
||||
|
||||
MccKeyValueHolder(MccKeyValueHolder&& other)
|
||||
{
|
||||
moveInst(std::move(other));
|
||||
};
|
||||
|
||||
MccKeyValueHolder& operator=(MccKeyValueHolder const& other)
|
||||
{
|
||||
copyInst(other);
|
||||
|
||||
return *this;
|
||||
};
|
||||
|
||||
MccKeyValueHolder& operator=(MccKeyValueHolder&& other)
|
||||
{
|
||||
moveInst(std::move(other));
|
||||
|
||||
return *this;
|
||||
};
|
||||
|
||||
constexpr std::array<std::string_view, NUMBER_OF_RECORDS> keys() const
|
||||
{
|
||||
return [this]<size_t... Is>(std::index_sequence<Is...>) {
|
||||
return std::array<std::string_view, NUMBER_OF_RECORDS>{std::get<Is>(_keyValue).key...};
|
||||
}(std::make_index_sequence<NUMBER_OF_RECORDS>{});
|
||||
}
|
||||
|
||||
|
||||
void setToDefaults()
|
||||
{
|
||||
[this]<size_t... Is>(std::index_sequence<Is...>) {
|
||||
((std::get<Is>(_keyValue).value = std::get<Is>(_keyValue).default_value), ...);
|
||||
}(std::make_index_sequence<NUMBER_OF_RECORDS>{});
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
// 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);
|
||||
// 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;
|
||||
// }
|
||||
// }
|
||||
|
||||
template <std::ranges::contiguous_range R, typename T>
|
||||
std::error_code setValue(R const& key, const T& value)
|
||||
{
|
||||
return setValue(std::string_view{key}, value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::error_code setValue(std::string_view key, const T& value)
|
||||
{
|
||||
const size_t hash = utils::FNV1aHash(key);
|
||||
|
||||
auto ec = forHash(hash, [&value](auto& rec) -> std::error_code {
|
||||
using VT = decltype(rec.value);
|
||||
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;
|
||||
}
|
||||
|
||||
return MccKeyValueHolderErrorCode::ERROR_OK;
|
||||
});
|
||||
|
||||
if (!ec) {
|
||||
_changedKey.insert(hash);
|
||||
}
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
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,
|
||||
size_t skip_records = 0, // number of skipped records (from the beginning)
|
||||
RecDelimT rec_delim = DEFAULT_RECORD_DELIMITER // records delimiter
|
||||
)
|
||||
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>>) {
|
||||
return fromCharRange(std::string_view{buffer}, std::string_view(rec_delim));
|
||||
} else {
|
||||
return fromCharRange(std::string_view{buffer}, std::move(rec_delim));
|
||||
}
|
||||
} else {
|
||||
if constexpr (std::is_array_v<std::decay_t<RecDelimT>>) {
|
||||
return fromCharRange(buffer, std::string_view(rec_delim));
|
||||
}
|
||||
}
|
||||
|
||||
std::error_code ec{};
|
||||
std::string_view rec, key, svalue, inline_comm;
|
||||
std::vector<std::optional<std::string>> head_comm;
|
||||
size_t key_hash;
|
||||
|
||||
_headComment.clear();
|
||||
_inlineComment.clear();
|
||||
_changedKey.clear();
|
||||
|
||||
// set values to its defaults
|
||||
setToDefaults();
|
||||
|
||||
auto recs = std::views::split(buffer, std::move(rec_delim)) | std::views::drop(skip_records);
|
||||
|
||||
for (auto const& el : recs) {
|
||||
rec = mcc::utils::trimSpaces(el, utils::TrimType::TRIM_LEFT);
|
||||
|
||||
inline_comm = {};
|
||||
|
||||
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.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(std::string{found.end(), rec.end()});
|
||||
}
|
||||
|
||||
rec = std::string_view(rec.begin(), found.begin());
|
||||
}
|
||||
|
||||
if (rec.size()) {
|
||||
found = std::ranges::search(rec, KEY_VALUE_DELIM);
|
||||
if (found.begin() != rec.begin()) {
|
||||
key = trimSpaces(std::string_view(rec.begin(), found.begin()), utils::TrimType::TRIM_RIGHT);
|
||||
svalue = std::string_view(found.end(), rec.end());
|
||||
|
||||
key_hash = utils::FNV1aHash(key);
|
||||
|
||||
ec = forHash(key_hash, [&key_hash, svalue, this]<typename REC_T>(REC_T& v) {
|
||||
using VT = decltype(v.value);
|
||||
auto err = MccDeserializer<VT>{}(svalue, v.value, v.serial_pars);
|
||||
if (err) {
|
||||
return MccKeyValueHolderErrorCode::ERROR_DESERIAL;
|
||||
}
|
||||
|
||||
_changedKey.insert(key_hash);
|
||||
|
||||
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)
|
||||
|
||||
} else { // empty record, just skip it (no error)
|
||||
// head_comm.push_back({el.begin(), el.end()});
|
||||
head_comm.push_back(std::nullopt);
|
||||
}
|
||||
}
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
template <OutputPolicy OPOLICY = MccKeyValueHolder::OPOLICY_CHANGED_ONLY,
|
||||
traits::mcc_output_char_range R,
|
||||
traits::mcc_input_char_range RecDelimT = std::string_view>
|
||||
std::error_code toCharRange(R& output_buffer, RecDelimT rec_delim = DEFAULT_RECORD_DELIMITER)
|
||||
{
|
||||
if (std::is_pointer_v<std::decay_t<RecDelimT>>) { // char*, const char*, char[], conat char[]
|
||||
return toCharRange(output_buffer, std::string_view{rec_delim});
|
||||
}
|
||||
|
||||
std::error_code ec{};
|
||||
|
||||
#ifdef __GNUG__
|
||||
// to fix GCC compilation crash for the versions < 16
|
||||
#if GCC_VERSION < 160000
|
||||
auto write_rec = [&output_buffer, &rec_delim, &ec, obj_ptr = this]<size_t I = 0>(this auto& self) -> void {
|
||||
#else
|
||||
auto write_rec = [&output_buffer, &rec_delim, &ec, this]<size_t I = 0>(this auto& self) -> void {
|
||||
#endif
|
||||
#endif
|
||||
if constexpr (I < NUMBER_OF_RECORDS) {
|
||||
if constexpr (OPOLICY == MccKeyValueHolder::OPOLICY_CHANGED_ONLY) {
|
||||
#ifdef __GNUG__
|
||||
// to fix GCC compilation crash for the versions < 16
|
||||
#if GCC_VERSION < 160000
|
||||
if (obj_ptr->_changedKey.count(obj_ptr->_hashes[I]) == 0) {
|
||||
#else
|
||||
if (_changedKey.count(_hashes[I]) == 0) {
|
||||
#endif
|
||||
#endif
|
||||
self.template operator()<I + 1>();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __GNUG__
|
||||
// to fix GCC compilation crash for the versions < 16
|
||||
#if GCC_VERSION < 160000
|
||||
ec = obj_ptr->template formatRecord<I>(output_buffer, rec_delim);
|
||||
#else
|
||||
ec = formatRecord<I>(output_buffer, rec_delim);
|
||||
#endif
|
||||
#endif
|
||||
if (ec) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.template operator()<I + 1>();
|
||||
}
|
||||
};
|
||||
|
||||
write_rec();
|
||||
|
||||
// [&write_rec]<size_t... Is>(std::index_sequence<Is...>) {
|
||||
// (write_rec.template operator()<Is>(), ...);
|
||||
// }(std::make_index_sequence<NUMBER_OF_RECORDS>());
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
protected:
|
||||
DESCR_T _keyValue;
|
||||
|
||||
std::array<size_t, NUMBER_OF_RECORDS> _hashes{}; // key hashes
|
||||
std::unordered_map<size_t, std::vector<std::optional<std::string>>>
|
||||
_headComment{}; // comment string/strings before key
|
||||
std::unordered_map<size_t, std::string> _inlineComment{}; // inline (after key=value pair) comment
|
||||
std::unordered_set<size_t> _changedKey{}; // loaded keys (see fromCharRange)
|
||||
|
||||
//
|
||||
// NOTE: deduced this is needed here to use "forKey" method in getter and setter (const and non-const contexts)!!!
|
||||
//
|
||||
|
||||
std::error_code forKey(this auto&& self, std::string_view key, auto&& func)
|
||||
{
|
||||
return std::forward<decltype(self)>(self).template forHash<0>(utils::FNV1aHash(key),
|
||||
std::forward<decltype(func)>(func));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 'func' signature:
|
||||
// std::error func(mcc_keyvalue_record_c&&)
|
||||
// e.g.:
|
||||
// [](auto const& rec)->std::error_code {}
|
||||
// [](auto& rec)->std::error_code {}
|
||||
//
|
||||
template <size_t I = 0>
|
||||
std::error_code forHash(this auto&& self, size_t hash, auto&& func)
|
||||
{
|
||||
if constexpr (I < NUMBER_OF_RECORDS) {
|
||||
if (hash == std::forward<decltype(self)>(self)._hashes[I]) {
|
||||
return std::forward<decltype(func)>(func)(std::get<I>(std::forward<decltype(self)>(self)._keyValue));
|
||||
} else {
|
||||
return std::forward<decltype(self)>(self).template forHash<I + 1>(hash,
|
||||
std::forward<decltype(func)>(func));
|
||||
}
|
||||
}
|
||||
|
||||
return MccKeyValueHolderErrorCode::ERROR_INVALID_KEY;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if constexpr (I < NUMBER_OF_RECORDS) {
|
||||
auto key = std::get<I>(_keyValue).key;
|
||||
using val_t = std::remove_cvref_t<decltype(std::get<I>(_keyValue).value)>;
|
||||
|
||||
const val_t& val = is_default ? std::get<I>(_keyValue).default_value : std::get<I>(_keyValue).value;
|
||||
|
||||
std::string buff;
|
||||
// auto err = MccSerializer<val_t>{}(buff, std::get<I>(_keyValue).value,
|
||||
// std::get<I>(_keyValue).serial_pars);
|
||||
auto err = MccSerializer<val_t>{}(buff, val, std::get<I>(_keyValue).serial_pars);
|
||||
if (err) {
|
||||
return MccKeyValueHolderErrorCode::ERROR_SERIAL;
|
||||
} else {
|
||||
size_t hash = _hashes[I];
|
||||
// write head comment
|
||||
if (_headComment[hash].size()) {
|
||||
for (auto const& comm : _headComment[hash]) {
|
||||
if (comm.has_value()) {
|
||||
std::format_to(std::back_inserter(output_buffer), "{}{}", COMM_SEQ, comm.value());
|
||||
}
|
||||
std::ranges::copy(rec_delim, std::back_inserter(output_buffer));
|
||||
}
|
||||
}
|
||||
|
||||
// key and value
|
||||
std::format_to(std::back_inserter(output_buffer), "{}{}{}", 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));
|
||||
}
|
||||
}
|
||||
|
||||
return MccKeyValueHolderErrorCode::ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
template <size_t I = 0>
|
||||
void copyInst(MccKeyValueHolder const& other)
|
||||
{
|
||||
if constexpr (I < NUMBER_OF_RECORDS) {
|
||||
// here one needs check equality of the keys!!!
|
||||
if (_hashes[I] == other._hashes[I]) {
|
||||
auto& orec = std::get<I>(other._keyValue);
|
||||
std::get<I>(_keyValue).value = orec.value;
|
||||
std::get<I>(_keyValue).default_value = orec.default_value;
|
||||
std::get<I>(_keyValue).serial_pars = orec.serial_pars;
|
||||
|
||||
if (auto it = other._headComment.find(_hashes[I]); it != other._headComment.end()) {
|
||||
_headComment[_hashes[I]] = it->second;
|
||||
}
|
||||
if (auto it = other._inlineComment.find(_hashes[I]); it != other._inlineComment.end()) {
|
||||
_inlineComment[_hashes[I]] = it->second;
|
||||
}
|
||||
|
||||
_changedKey.insert(_hashes[I]);
|
||||
}
|
||||
|
||||
copyInst<I + 1>(other);
|
||||
}
|
||||
}
|
||||
|
||||
template <size_t I = 0>
|
||||
void moveInst(MccKeyValueHolder&& other)
|
||||
{
|
||||
if constexpr (I < NUMBER_OF_RECORDS) {
|
||||
// here one needs check equality of the keys!!!
|
||||
if (_hashes[I] == other._hashes[I]) {
|
||||
auto& orec = std::get<I>(other._keyValue);
|
||||
std::get<I>(_keyValue).value = std::move(orec.value);
|
||||
std::get<I>(_keyValue).default_value = std::move(orec.default_value);
|
||||
std::get<I>(_keyValue).serial_pars = std::move(orec.serial_pars);
|
||||
|
||||
if (auto it = other._headComment.find(_hashes[I]); it != other._headComment.end()) {
|
||||
_headComment[_hashes[I]] = std::move(it->second);
|
||||
}
|
||||
if (auto it = other._inlineComment.find(_hashes[I]); it != other._inlineComment.end()) {
|
||||
_inlineComment[_hashes[I]] = std::move(it->second);
|
||||
}
|
||||
|
||||
_changedKey.insert(_hashes[I]);
|
||||
}
|
||||
|
||||
moveInst<I + 1>(other);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <mcc_record_value_c T>
|
||||
struct mcc_simple_kv_record_t {
|
||||
const std::string_view key;
|
||||
T value, default_value;
|
||||
mcc_serialization_params_t serial_pars;
|
||||
};
|
||||
|
||||
template <mcc_record_value_c T>
|
||||
static mcc_simple_kv_record_t<T> mcc_make_simple_kv_record(
|
||||
std::string_view key,
|
||||
T const& def_value,
|
||||
mcc_serialization_params_t const& spars = mcc_serialization_params_t{})
|
||||
{
|
||||
return mcc_simple_kv_record_t<T>{key, def_value, def_value, spars};
|
||||
}
|
||||
|
||||
} // namespace mcc::impl
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
#include "mcc_concepts.h"
|
||||
#include "mcc_coordinate.h"
|
||||
#include "mcc_deserializer.h"
|
||||
#include "mcc_serializer.h"
|
||||
|
||||
namespace mcc::impl
|
||||
{
|
||||
@@ -104,6 +106,24 @@ class is_error_code_enum<mcc::impl::MccDefaultPCMErrorCode> : public true_type
|
||||
namespace mcc::impl
|
||||
{
|
||||
|
||||
// The routine generates a sequence of length 'innerN'+2 elements.
|
||||
// Th e first element is 'start_border' and the last one is 'stop_border'
|
||||
// (i.e. it returns at least 2-elements std::vector)
|
||||
// 'innerN' is a number of inner elements
|
||||
static std::vector<double> mccGenerateBsplineKnots(double start_border, double stop_border, size_t innerN)
|
||||
{
|
||||
std::vector<double> res(innerN + 2);
|
||||
res.front() = start_border;
|
||||
res.back() = stop_border;
|
||||
|
||||
if (innerN) {
|
||||
const double step = (stop_border - start_border) / (innerN + 1);
|
||||
std::ranges::for_each(std::views::iota(1, (int)innerN + 1),
|
||||
[&](auto const& i) { res[i] = start_border + i * step; });
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// type of PCM corrections (algorithm used):
|
||||
// PCM_TYPE_GEOMETRY - "classic" geometry-based correction coefficients
|
||||
@@ -131,6 +151,48 @@ static constexpr std::string_view mccDefaultPCMTypeString(MccDefaultPCMType type
|
||||
: "UNKNOWN";
|
||||
}
|
||||
|
||||
template <>
|
||||
struct MccSerializer<MccDefaultPCMType> : MccSerializerBase {
|
||||
constexpr static std::string_view serializerName{"MCC-DEFAULT-PCMTYPE-SERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output,
|
||||
MccDefaultPCMType const& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
std::ranges::copy(mccDefaultPCMTypeString(value), std::back_inserter(output));
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct MccDeserializer<MccDefaultPCMType> : MccDeserializerBase {
|
||||
static constexpr std::string_view deserializerName{"MCC-COORD-EPOCH-DESERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input,
|
||||
MccDefaultPCMType& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
auto s = mcc::utils::trimSpaces(input);
|
||||
|
||||
if (s == mcc::impl::MccDefaultPCMTypeString<mcc::impl::MccDefaultPCMType::PCM_TYPE_GEOMETRY>) {
|
||||
value = mcc::impl::MccDefaultPCMType::PCM_TYPE_GEOMETRY;
|
||||
} else if (s == mcc::impl::MccDefaultPCMTypeString<mcc::impl::MccDefaultPCMType::PCM_TYPE_GEOMETRY_BSPLINE>) {
|
||||
value = mcc::impl::MccDefaultPCMType::PCM_TYPE_GEOMETRY;
|
||||
} else if (s == mcc::impl::MccDefaultPCMTypeString<mcc::impl::MccDefaultPCMType::PCM_TYPE_BSPLINE>) {
|
||||
value = mcc::impl::MccDefaultPCMType::PCM_TYPE_BSPLINE;
|
||||
} else {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <MccMountType MOUNT_TYPE>
|
||||
class MccDefaultPCM : public mcc_pcm_interface_t<std::error_code>
|
||||
{
|
||||
|
||||
@@ -13,12 +13,14 @@
|
||||
#include "mcc_concepts.h"
|
||||
#include "mcc_constants.h"
|
||||
#include "mcc_coordinate.h"
|
||||
#include "mcc_deserializer.h"
|
||||
#include "mcc_serializer.h"
|
||||
|
||||
namespace mcc::impl
|
||||
{
|
||||
|
||||
|
||||
enum class MccPZoneErrorCode : int { ERROR_OK, ERROR_NULLPTR, ERROR_COORD_TRANSFROM, ERROR_PCM_COMP };
|
||||
enum class MccPZoneErrorCode : int { ERROR_OK, ERROR_NULLPTR, ERROR_COORD_TRANSFROM, ERROR_NO_PCM, ERROR_PCM_COMP };
|
||||
|
||||
} // namespace mcc::impl
|
||||
|
||||
@@ -56,6 +58,8 @@ struct MccPZoneCategory : public std::error_category {
|
||||
return "input argument os nullptr";
|
||||
case MccPZoneErrorCode::ERROR_COORD_TRANSFROM:
|
||||
return "coordinate transformation error";
|
||||
case MccPZoneErrorCode::ERROR_NO_PCM:
|
||||
return "PCM was not set";
|
||||
case MccPZoneErrorCode::ERROR_PCM_COMP:
|
||||
return "PCM computation error";
|
||||
default:
|
||||
@@ -89,6 +93,7 @@ public:
|
||||
|
||||
MccAltLimitPZ(mcc_angle_c auto const& alt_limit, mcc_angle_c auto const& latitude)
|
||||
: _altLimit(MccAngle(alt_limit).normalize<MccAngle::NORM_KIND_90_90>()),
|
||||
_latitude(MccAngle::normalizeAngle<MccAngle::NORM_KIND_90_90>(latitude)),
|
||||
_cosALim(cos(_altLimit)),
|
||||
_sinAlim(sin(_altLimit)),
|
||||
_cosLat(cos(latitude)),
|
||||
@@ -106,6 +111,32 @@ public:
|
||||
: KIND == MccAltLimitKind::MAX_ALT_LIMIT ? "MAXALT-ZONE"
|
||||
: "ALTLIMIT-UNKNOWN";
|
||||
|
||||
MccAltLimitPZ& operator=(MccAltLimitPZ&&) = default;
|
||||
MccAltLimitPZ& operator=(const MccAltLimitPZ&) = default;
|
||||
|
||||
template <mcc_angle_c T>
|
||||
T altLimit() const
|
||||
requires(!std::derived_from<T, MccAngle>)
|
||||
{
|
||||
return _altLimit;
|
||||
}
|
||||
|
||||
MccAngle altLimit() const
|
||||
{
|
||||
return _altLimit;
|
||||
}
|
||||
|
||||
template <mcc_angle_c T>
|
||||
T latitude() const
|
||||
requires(!std::derived_from<T, MccAngle>)
|
||||
{
|
||||
return _latitude;
|
||||
}
|
||||
|
||||
MccAngle latitude() const
|
||||
{
|
||||
return _latitude;
|
||||
}
|
||||
|
||||
error_t inPZone(mcc_skypoint_c auto const& coords, bool* result)
|
||||
{
|
||||
@@ -230,7 +261,7 @@ public:
|
||||
|
||||
protected:
|
||||
double _altLimit, _cosALim, _sinAlim;
|
||||
double _cosLat, _sinLat, _absLat, _latLim;
|
||||
double _latitude, _cosLat, _sinLat, _absLat, _latLim;
|
||||
|
||||
bool doesObjectReachZone(const double& dec_app)
|
||||
{
|
||||
@@ -321,15 +352,88 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(std::is_copy_assignable_v<MccAltLimitPZ<MccAltLimitKind::MIN_ALT_LIMIT>>);
|
||||
|
||||
/*
|
||||
to be serialized in format:
|
||||
ALT-LIMIT<seq-delim>LATITUDE
|
||||
*/
|
||||
template <MccAltLimitKind KIND>
|
||||
struct MccSerializer<MccAltLimitPZ<KIND>> : MccSerializerBase {
|
||||
constexpr static std::string_view serializerName{"MCC-ALTITUDE-PZONE-SERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output,
|
||||
MccAltLimitPZ<KIND> const& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
MccSerializer<MccAngle> aser;
|
||||
|
||||
auto err = aser(output, value.altLimit(), params);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", params.seq_delim);
|
||||
|
||||
err = aser(output, value.latitude(), params);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
template <MccAltLimitKind KIND>
|
||||
struct MccDeserializer<MccAltLimitPZ<KIND>> : MccDeserializerBase {
|
||||
static constexpr std::string_view deserializerName{"MCC-ALTITUDE-PZONE-DESERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input,
|
||||
MccAltLimitPZ<KIND>& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
std::vector<std::string_view> s;
|
||||
MccDeserializer<MccAngle> ades;
|
||||
|
||||
auto seq = std::views::split(input, params.seq_delim);
|
||||
if (std::ranges::distance(seq.begin(), seq.end()) > 1) {
|
||||
for (auto const& seq_el : seq) {
|
||||
s.push_back(utils::trimSpaces(seq_el, utils::TrimType::TRIM_BOTH));
|
||||
}
|
||||
|
||||
MccAngle alt, lat;
|
||||
|
||||
auto err = ades(s[0], alt, params);
|
||||
if (err) {
|
||||
return MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER;
|
||||
}
|
||||
|
||||
err = ades(s[1], lat, params);
|
||||
if (err) {
|
||||
return MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER;
|
||||
}
|
||||
|
||||
value = MccAltLimitPZ<KIND>(alt, lat);
|
||||
} else {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* co-longitude axis (HA or AZ) limit switch prohibited zone */
|
||||
|
||||
/* co-longitude axis (HA or AZ) and co-latitude (DEC, ZD) limit switch prohibited zone */
|
||||
|
||||
template <MccCoordKind AXIS_KIND>
|
||||
class MccAxisLimitSwitchPZ : public mcc_pzone_interface_t<std::error_code>
|
||||
{
|
||||
public:
|
||||
static_assert(AXIS_KIND == MccCoordKind::COORDS_KIND_AZ || AXIS_KIND == MccCoordKind::COORDS_KIND_HA_OBS,
|
||||
static_assert(AXIS_KIND == MccCoordKind::COORDS_KIND_AZ || AXIS_KIND == MccCoordKind::COORDS_KIND_HA_OBS ||
|
||||
AXIS_KIND == MccCoordKind::COORDS_KIND_ZD || AXIS_KIND == MccCoordKind::COORDS_KIND_DEC_OBS,
|
||||
"UNSUPPORTED AXIS TYPE!");
|
||||
|
||||
typedef std::error_code error_t;
|
||||
@@ -339,33 +443,89 @@ public:
|
||||
static constexpr MccProhibitedZonePolicy pzPolicy = MccProhibitedZonePolicy::PZ_POLICY_FLIP;
|
||||
|
||||
//
|
||||
// min_limit_val and max_limit_val are hardware encoder angles in radians!
|
||||
// min_limit_val and max_limit_val are hardware encoder angles!
|
||||
// pcm is nullptr or pointer to mcc_pcm_c
|
||||
//
|
||||
MccAxisLimitSwitchPZ(mcc_angle_c auto const& min_limit_val,
|
||||
mcc_angle_c auto const& max_limit_val,
|
||||
mcc_pcm_c auto* pcm)
|
||||
template <typename PCM_T>
|
||||
MccAxisLimitSwitchPZ(mcc_angle_c auto const& min_limit_val, mcc_angle_c auto const& max_limit_val, PCM_T pcm)
|
||||
requires(std::is_null_pointer_v<PCM_T> || mcc_pcm_c<std::remove_pointer_t<PCM_T>>)
|
||||
: _minLimit(min_limit_val), _maxLimit(max_limit_val)
|
||||
{
|
||||
_correctForPCM = [pcm](MccSkyPoint const& skypt, MccGenXY* hw_coords) {
|
||||
struct pcm_res_t {
|
||||
double pcmX, pcmY;
|
||||
if constexpr (std::is_null_pointer_v<PCM_T>) {
|
||||
_correctForPCM = [](MccSkyPoint const&, MccGenXY*) -> error_t { return MccPZoneErrorCode::ERROR_NO_PCM; };
|
||||
} else {
|
||||
_correctForPCM = [pcm](MccSkyPoint const& skypt, MccGenXY* hw_coords) {
|
||||
struct pcm_res_t {
|
||||
double pcmX, pcmY;
|
||||
};
|
||||
|
||||
pcm_res_t res;
|
||||
|
||||
auto err = pcm->computeInversePCM(skypt, &res, hw_coords);
|
||||
|
||||
return mcc_deduced_err(err, MccPZoneErrorCode::ERROR_PCM_COMP);
|
||||
};
|
||||
|
||||
pcm_res_t res;
|
||||
|
||||
auto err = pcm->computeInversePCM(skypt, &res, hw_coords);
|
||||
|
||||
return mcc_deduced_err(err, MccPZoneErrorCode::ERROR_PCM_COMP);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static constexpr std::string_view pzoneName = axisKind == MccCoordKind::COORDS_KIND_AZ ? "AZ_AXIS-LIMITSWITCH_ZONE"
|
||||
: axisKind == MccCoordKind::COORDS_KIND_HA_OBS
|
||||
? "HA_AXIS-LIMITSWITCH_ZONE"
|
||||
: "UKNOWN";
|
||||
static constexpr std::string_view pzoneName =
|
||||
axisKind == MccCoordKind::COORDS_KIND_AZ ? "AZ-AXIS-LIMITSWITCH-ZONE"
|
||||
: axisKind == MccCoordKind::COORDS_KIND_HA_OBS ? "HA-AXIS-LIMITSWITCH-ZONE"
|
||||
: axisKind == MccCoordKind::COORDS_KIND_ZD ? "ZD-AXIS-LIMITSWITCH-ZONE"
|
||||
: axisKind == MccCoordKind::COORDS_KIND_DEC_OBS ? "DEC-AXIS-LIMITSWITCH-ZONE"
|
||||
: "UKNOWN";
|
||||
|
||||
MccAxisLimitSwitchPZ(const MccAxisLimitSwitchPZ&) = default;
|
||||
MccAxisLimitSwitchPZ(MccAxisLimitSwitchPZ&&) = default;
|
||||
|
||||
MccAxisLimitSwitchPZ& operator=(const MccAxisLimitSwitchPZ&) = default;
|
||||
MccAxisLimitSwitchPZ& operator=(MccAxisLimitSwitchPZ&&) = default;
|
||||
|
||||
template <mcc_angle_c T>
|
||||
T minLimit() const
|
||||
requires(!std::derived_from<T, MccAngle>)
|
||||
{
|
||||
return _minLimit;
|
||||
}
|
||||
|
||||
MccAngle minLimit() const
|
||||
{
|
||||
return _minLimit;
|
||||
}
|
||||
|
||||
template <mcc_angle_c T>
|
||||
T maxLimit() const
|
||||
requires(!std::derived_from<T, MccAngle>)
|
||||
{
|
||||
return _maxLimit;
|
||||
}
|
||||
|
||||
MccAngle maxLimit() const
|
||||
{
|
||||
return _maxLimit;
|
||||
}
|
||||
|
||||
template <typename PCM_T>
|
||||
void setPCM(PCM_T pcm)
|
||||
requires(std::is_null_pointer_v<PCM_T> || mcc_pcm_c<std::remove_pointer_t<PCM_T>>)
|
||||
{
|
||||
if constexpr (std::is_null_pointer_v<PCM_T>) {
|
||||
_correctForPCM = [](MccSkyPoint const&, MccGenXY*) -> error_t { return MccPZoneErrorCode::ERROR_NO_PCM; };
|
||||
} else {
|
||||
_correctForPCM = [pcm](MccSkyPoint const& skypt, MccGenXY* hw_coords) {
|
||||
struct pcm_res_t {
|
||||
double pcmX, pcmY;
|
||||
};
|
||||
|
||||
pcm_res_t res;
|
||||
|
||||
auto err = pcm->computeInversePCM(skypt, &res, hw_coords);
|
||||
|
||||
return mcc_deduced_err(err, MccPZoneErrorCode::ERROR_PCM_COMP);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
error_t inPZone(mcc_skypoint_c auto const& coords, bool* result)
|
||||
{
|
||||
@@ -430,15 +590,36 @@ protected:
|
||||
coords.to(xy);
|
||||
}
|
||||
|
||||
double x = xy.x();
|
||||
|
||||
if constexpr (AXIS_KIND == MccCoordKind::COORDS_KIND_HA_OBS) {
|
||||
double x = xy.x();
|
||||
|
||||
if (from_time) { // timeFromPZone
|
||||
time_ang = (_minLimit - x) / MCC_SIDERAL_TO_UT1_RATIO; // to UT1 scale
|
||||
} else { // timeToPZone
|
||||
time_ang = (_maxLimit - x) / MCC_SIDERAL_TO_UT1_RATIO; // to UT1 scale
|
||||
}
|
||||
} else if constexpr (AXIS_KIND == MccCoordKind::COORDS_KIND_DEC_OBS) {
|
||||
double y = xy.y();
|
||||
|
||||
// TODO: !!!!!!!!!!!!!!!!!!!!!!!!
|
||||
// assume here sideral speed moving! so, observed DEC is near constant
|
||||
if (from_time) { // timeFromPZone
|
||||
if (y < _minLimit || y > _maxLimit) {
|
||||
time_ang = std::numeric_limits<double>::max();
|
||||
} else {
|
||||
time_ang = 0;
|
||||
}
|
||||
} else { // timeToPZone
|
||||
if (y < _minLimit || y > _maxLimit) { // already in the zone
|
||||
time_ang = 0;
|
||||
} else {
|
||||
time_ang = std::numeric_limits<double>::max();
|
||||
}
|
||||
}
|
||||
} else if constexpr (AXIS_KIND == MccCoordKind::COORDS_KIND_AZ) {
|
||||
static_assert(false, "NOT IMPLEMENTED YET!!!");
|
||||
} else {
|
||||
static_assert(false, "NOT IMPLEMENTED YET!!!");
|
||||
}
|
||||
|
||||
std::chrono::nanoseconds ns{
|
||||
@@ -451,5 +632,81 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(std::is_copy_assignable_v<MccAxisLimitSwitchPZ<MccCoordKind::COORDS_KIND_HA_OBS>>);
|
||||
static_assert(std::is_copy_assignable_v<MccAxisLimitSwitchPZ<MccCoordKind::COORDS_KIND_DEC_OBS>>);
|
||||
|
||||
/*
|
||||
to be serialized in format:
|
||||
MIN_LIMIT<seq-delim>MAX_LIMIT
|
||||
*/
|
||||
template <MccCoordKind AXIS_KIND>
|
||||
struct MccSerializer<MccAxisLimitSwitchPZ<AXIS_KIND>> : MccSerializerBase {
|
||||
constexpr static std::string_view serializerName{"MCC-AXIS-LIMIT-SWITCH-SERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_output_char_range auto& output,
|
||||
MccAxisLimitSwitchPZ<AXIS_KIND> const& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
MccSerializer<MccAngle> aser;
|
||||
|
||||
auto err = aser(output, value.minLimit(), params);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
std::format_to(std::back_inserter(output), "{}", params.seq_delim);
|
||||
|
||||
err = aser(output, value.maxLimit(), params);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccSerializerErrorCode::ERROR_UNDERLYING_SERIALIZER);
|
||||
}
|
||||
|
||||
|
||||
return MccSerializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <MccCoordKind AXIS_KIND>
|
||||
struct MccDeserializer<MccAxisLimitSwitchPZ<AXIS_KIND>> : MccDeserializerBase {
|
||||
static constexpr std::string_view deserializerName{"MCC-AXIS-LIMIT-SWITCH-DESERIALIZER"};
|
||||
|
||||
template <mcc_serialization_params_c ParamsT = mcc_serialization_params_t>
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input,
|
||||
MccAxisLimitSwitchPZ<AXIS_KIND>& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
std::vector<std::string_view> s;
|
||||
MccDeserializer<MccAngle> ades;
|
||||
|
||||
auto seq = std::views::split(input, params.seq_delim);
|
||||
// if (std::ranges::size(seq) < 2) {
|
||||
if (std::ranges::distance(seq.begin(), seq.end()) > 1) {
|
||||
for (auto const& seq_el : seq) {
|
||||
s.push_back(utils::trimSpaces(seq_el, utils::TrimType::TRIM_BOTH));
|
||||
}
|
||||
|
||||
MccAngle minLim, maxLim;
|
||||
|
||||
auto err = ades(s[0], minLim, params);
|
||||
if (err) {
|
||||
return MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER;
|
||||
}
|
||||
|
||||
err = ades(s[1], maxLim, params);
|
||||
if (err) {
|
||||
return MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER;
|
||||
}
|
||||
|
||||
// WARNING: the class below is created without the PCM-class pointer!!!
|
||||
value = MccAxisLimitSwitchPZ<AXIS_KIND>(minLim, maxLim, nullptr);
|
||||
} else {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mcc::impl
|
||||
|
||||
@@ -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>
|
||||
|
||||
178
tests/mcc_keyvalue_test.cpp
Normal file
178
tests/mcc_keyvalue_test.cpp
Normal file
@@ -0,0 +1,178 @@
|
||||
#include <print>
|
||||
|
||||
#include <mcc/mcc_keyvalue.h>
|
||||
|
||||
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{}},
|
||||
mcc_simple_kv_record_t{"cc", MccCelestialCoordEpoch{}, MccCelestialCoordEpoch{}, mcc_serialization_params_t{}},
|
||||
mcc_simple_kv_record_t{
|
||||
"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("vt", VT(77)),
|
||||
mcc_make_simple_kv_record("sarr", std::array<double, 3>{1, 2, 3}));
|
||||
|
||||
|
||||
|
||||
static std::string STR = R"--(
|
||||
|
||||
aaa = dewl_ewkj23+23998
|
||||
|
||||
#
|
||||
# this is angle
|
||||
bb=1.24534
|
||||
cc= 2026-05-15T05:53:20.921723918 # date UTC
|
||||
|
||||
)--";
|
||||
|
||||
static std::string STR1 = R"--(
|
||||
aaa = dewl_ewkj23+23998
|
||||
|
||||
#
|
||||
# this is obs date
|
||||
cc= 2026-05-15T05:53:20.921723918 # date UTC
|
||||
|
||||
ddd = 01:02:33.434 # HA in hours:mins:secs
|
||||
)--";
|
||||
|
||||
int main()
|
||||
{
|
||||
std::error_code err;
|
||||
std::string buff;
|
||||
|
||||
MccKeyValueHolder kv(kv_desc);
|
||||
|
||||
err = kv.toCharRange(buff);
|
||||
if (err) {
|
||||
std::println("ERR = {}", err);
|
||||
return 1;
|
||||
}
|
||||
std::println("DEFAULT VALUES:");
|
||||
std::println("--(\n{})--", buff);
|
||||
std::println("\n\n");
|
||||
|
||||
|
||||
err = kv.setValue("eee", 15.1515);
|
||||
if (err) {
|
||||
std::println("ERR = {}", err);
|
||||
// return 1;
|
||||
}
|
||||
|
||||
// auto err = kv.fromCharRange(STR);
|
||||
err = kv.fromCharRange(STR1);
|
||||
if (err) {
|
||||
std::println("ERR = {}", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::println("{} = {}", "bb", kv.getValue<MccAngle>(std::string{"bb"}).value().sexagesimal());
|
||||
std::println("{} = {}", "cc", kv.getValue<MccCelestialCoordEpoch>("cc").value().UTC());
|
||||
|
||||
err = kv.setValue("cc", std::chrono::system_clock::now());
|
||||
if (err) {
|
||||
std::println("ERR = {}", err);
|
||||
// return 1;
|
||||
}
|
||||
|
||||
err = kv.setValue("aaa", "OK");
|
||||
if (err) {
|
||||
std::println("ERR = {}", err);
|
||||
// return 1;
|
||||
}
|
||||
|
||||
err = kv.setValue("ddd", 37.5_degs);
|
||||
if (err) {
|
||||
std::println("ERR = {}", err);
|
||||
// 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("------------------------------------");
|
||||
|
||||
|
||||
buff.clear();
|
||||
err = kv.toCharRange<decltype(kv)::OPOLICY_FULL>(buff);
|
||||
// err = kv.toCharRange(buff);
|
||||
if (err) {
|
||||
std::println("ERR = {}", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::println("--(\n{}\n)--", buff);
|
||||
|
||||
std::print("KEYS: ");
|
||||
for (auto const& k : kv.keys()) {
|
||||
std::print("{} ", k);
|
||||
}
|
||||
std::println("");
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user