Compare commits

...

21 Commits

Author SHA1 Message Date
cd97ed875f update mcc_ccte_iers_default.h 2026-06-06 10:55:04 +03:00
b3c7584205 fix 2026-06-05 09:49:18 +03:00
5984bc5204 mcc_keyvalue.h: add fix to prevent GCC compilation crashing 2026-06-05 09:44:30 +03:00
d865e51ffb ... 2026-06-03 12:06:01 +03:00
6e6f230f4d mcc_keyvalue.h: fix "-Wsubobject-linkage" GCC-warning 2026-06-02 12:05:26 +03:00
a1f17f0d76 mcc_keyvalue.h: fix MccKeyValueHolder class coping and moving
mcc_pzone.h: add copy and move constructors and operator=
2026-06-02 10:53:40 +03:00
e1a136a839 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
2026-05-28 17:39:30 +03:00
3497850e1f ... 2026-05-27 16:18:11 +03:00
e9c329d88f mcc_bsplines.h: fixes (use right macro names for the Fortran subroutines) 2026-05-23 11:17:51 +03:00
445a029a2f mcc_bsplines.h: use of FC_GLOBAL macro to correct call FITPACK
subroutines mangled names
fitpack/CMakeLists.txt: add non-empty SYMBOL_NAMESPACE to fix generated
'insert' macro (interference with STL containers 'insert' methods) macro
issue
various fixes
2026-05-22 12:51:33 +03:00
8e5e3631ba fixes 2026-05-22 09:28:25 +03:00
304464dbda fixes 2026-05-21 18:27:43 +03:00
4b5a390987 mcc_pzone.h: add serializer/deserializer of the implemented prohibited
zone clases
mcc_pcm.h: add mccGenerateBsplineKnots function
mcc_deserializer.h: fixes
2026-05-21 12:20:32 +03:00
47ba7342e7 fix 2026-05-20 17:57:18 +03:00
c5f17b7403 mcc_pcm.h: add serializer and deserializer of the MccDefaultPCM enum 2026-05-19 17:24:14 +03:00
8d36444c51 mcc_keyvalue.h: worked 2026-05-19 12:16:22 +03:00
d40ecb5df7 ... 2026-05-18 17:19:40 +03:00
d8130cede2 mcc_keyvalue.h: add serial_pars field to mcc_keyvalue_record_c concept,
rewrite MccKeyValueHolder class methods accordinally
2026-05-18 12:21:53 +03:00
056c152d49 mcc_keyvalue.h: worked 2026-05-18 11:24:17 +03:00
Timur A. Fatkhullin
9630751a4d mcc_epoch.h: fix operator=(std::chrono::time_point)
class MccKeyValueHolder: developing ...
2026-05-17 22:33:31 +03:00
3dbe4c12b7 mcc_keyvalue.h: developing ... 2026-05-16 15:08:09 +03:00
11 changed files with 1604 additions and 722 deletions

View File

@@ -355,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)

View File

@@ -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}
)

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -11,7 +11,9 @@
****************************************************************************************/
#include "mcc_constants.h"
#include <unordered_map>
#include <unordered_set>
#include "mcc_deserializer.h"
#include "mcc_serializer.h"
#include "mcc_utils.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
@@ -41,12 +49,12 @@ namespace mcc::impl
struct MccKeyValueHolderCategory : public std::error_category {
MccKeyValueHolderCategory() : std::error_category() {}
const char* name() const noexcept
const char* name() const noexcept override
{
return "MCC-KEYVALUEHOLDER-ERR-CATEGORY";
}
std::string message(int ec) const
std::string message(int ec) const override
{
MccKeyValueHolderErrorCode err = static_cast<MccKeyValueHolderErrorCode>(ec);
@@ -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";
}
@@ -80,68 +90,117 @@ inline std::error_code make_error_code(MccKeyValueHolderErrorCode ec)
// to follow std::variant requirements (not references, not array, not void)
template <typename T>
concept mcc_variant_valid_type_c = requires { !std::is_array_v<T> && !std::is_void_v<T> && !std::is_reference_v<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), std::string_view>;
requires mcc_variant_valid_type_c<decltype(t.value)>;
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); };
namespace constants
{
static constexpr char MCC_KV_COMMENT_SEQ_ARR[] = "#";
static constexpr char MCC_KV_KEY_VALUE_DELIM_SEQ_ARR[] = "=";
static constexpr char MCC_KV_VALUE_ARRAY_DELIM_SEQ_ARR[] = ",";
} // namespace constants
// 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 = constants::MCC_KV_COMMENT_SEQ_ARR,
const char* KV_DELIM = constants::MCC_KV_KEY_VALUE_DELIM_SEQ_ARR,
const char* ARR_DELIM = constants::MCC_KV_VALUE_ARRAY_DELIM_SEQ_ARR>
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:
static constexpr std::string_view COMMENT_SEQ{COMM_SEQ == nullptr ? constants::MCC_KV_COMMENT_SEQ_ARR
: COMM_SEQ[0] == '\0' ? constants::MCC_KV_COMMENT_SEQ_ARR
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 ? constants::MCC_KV_KEY_VALUE_DELIM_SEQ_ARR
: KV_DELIM[0] == '\0' ? constants::MCC_KV_KEY_VALUE_DELIM_SEQ_ARR
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 std::string_view VALUE_ARRAY_DELIM{
ARR_DELIM == nullptr ? constants::MCC_KV_VALUE_ARRAY_DELIM_SEQ_ARR
: ARR_DELIM[0] == '\0' ? constants::MCC_KV_VALUE_ARRAY_DELIM_SEQ_ARR
: ARR_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<std::tuple_size_v<DESCR_T>>());
}(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
{
T v;
auto err = forKey(key, [&v]<typename VT>(const VT& val) -> std::error_code {
if constexpr (std::convertible_to<VT, T>) {
v = val;
} else if constexpr (std::constructible_from<T, VT>) {
v = T(val);
// 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;
}
@@ -152,33 +211,107 @@ public:
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)
{
return forKey(key, [value]<typename VT>(VT& val) -> std::error_code {
if constexpr (std::convertible_to<T, VT>) {
val = 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>) {
val = VT(value);
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 <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"),
SerParamsT const& ser_params = mcc_serialization_params_t{})
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>>) {
@@ -193,50 +326,147 @@ public:
}
std::error_code ec{};
std::string_view rec, key, value;
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);
auto recs = std::views::split(buffer, std::move(rec_delim));
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.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()) { // 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());
svalue = 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 = 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)
} // 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()});
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, std::tuple_size_v<DESCR_T>> _hashes;
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)!!!
@@ -249,13 +479,19 @@ protected:
}
//
// '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 < std::tuple_size_v<DESCR_T>) {
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).value);
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));
@@ -264,7 +500,116 @@ protected:
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

View File

@@ -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>
{

View File

@@ -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

View File

@@ -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
View 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;
}