...
This commit is contained in:
@@ -1,23 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
/****************************************************************************************
|
||||
* *
|
||||
* MOUNT CONTROL COMPONENTS LIBRARY *
|
||||
* *
|
||||
* *
|
||||
* IMPLEMENTATION OF DESERIALIZER CLASSES *
|
||||
* *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <string_view>
|
||||
|
||||
#include "mcc_concepts.h"
|
||||
#include "mcc_coordinate.h"
|
||||
#include "mcc_epoch.h"
|
||||
#include "mcc_error.h"
|
||||
#include "mcc_serialization_common.h"
|
||||
|
||||
namespace mcc::impl
|
||||
{
|
||||
@@ -89,34 +76,11 @@ inline std::error_code make_error_code(MccDeserializerErrorCode ec)
|
||||
}
|
||||
|
||||
|
||||
template <mcc_error_c RetT>
|
||||
struct mcc_deserializer_interface_t {
|
||||
virtual ~mcc_deserializer_interface_t() = default;
|
||||
|
||||
typedef RetT error_t;
|
||||
/* BASE DESERIALIZER CLASS (FOR IMPLEMENTATIONS BELOW) */
|
||||
|
||||
template <std::derived_from<mcc_deserializer_interface_t> SelfT,
|
||||
traits::mcc_input_char_range R,
|
||||
typename ValueT,
|
||||
typename... DeserParamsT>
|
||||
RetT operator()(this SelfT&& self, R const& input, ValueT& value, DeserParamsT&&... params)
|
||||
{
|
||||
return std::forward<SelfT>(self)(input, value);
|
||||
}
|
||||
|
||||
protected:
|
||||
mcc_deserializer_interface_t() = default;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept mcc_deserializer_c = std::derived_from<T, mcc_deserializer_interface_t<typename T::error_t>>;
|
||||
|
||||
|
||||
namespace details
|
||||
{
|
||||
|
||||
struct MccDeserializerBase : mcc_deserializer_interface_t<impl::MccError>, utils::mcc_elem_sequence_with_delim_t {
|
||||
using typename mcc_deserializer_interface_t<impl::MccError>::error_t;
|
||||
struct MccDeserializerBase : mcc_deserializer_interface_t<MccError> {
|
||||
using typename mcc_deserializer_interface_t<MccError>::error_t;
|
||||
|
||||
virtual ~MccDeserializerBase() = default;
|
||||
|
||||
@@ -127,14 +91,18 @@ protected:
|
||||
//
|
||||
// empty == true, if the 'input' is empty or if all elements consist of only spaces
|
||||
//
|
||||
std::vector<std::string_view> splitAggregateValue(traits::mcc_input_char_range auto const& input, bool& empty) const
|
||||
static std::vector<std::string_view> splitValueIntoElements(traits::mcc_input_char_range auto const& input,
|
||||
mcc_serialization_params_c auto const& params,
|
||||
bool& empty)
|
||||
{
|
||||
static_assert(std::ranges::contiguous_range<decltype(input)>, "NOT IMPLEMENTED FOR NON-CONTIGUIUS RANGES!!!");
|
||||
|
||||
std::vector<std::string_view> res;
|
||||
|
||||
if (std::ranges::size(input)) {
|
||||
empty = true;
|
||||
|
||||
std::ranges::for_each(std::views::split(input, this->_elementDelimiter), [&res, &empty](auto const& el) {
|
||||
std::ranges::for_each(std::views::split(input, params.elem_delim), [&res, &empty](auto const& el) {
|
||||
std::back_inserter(res) = utils::trimSpaces(std::string_view{el.begin(), el.end()});
|
||||
if (empty && res.back().size()) {
|
||||
empty = false;
|
||||
@@ -148,17 +116,17 @@ protected:
|
||||
}
|
||||
|
||||
template <typename VT, std::ranges::output_range<VT> R, typename... DeserParamsT>
|
||||
error_t deserializingRange(mcc_deserializer_c auto& dsr,
|
||||
traits::mcc_input_char_range auto const& input,
|
||||
R& r,
|
||||
DeserParamsT&&... params) const
|
||||
static error_t deserializingRange(mcc_deserializer_c auto& dsr,
|
||||
traits::mcc_input_char_range auto const& input,
|
||||
R& r,
|
||||
mcc_serialization_params_c auto const& params)
|
||||
{
|
||||
if (std::ranges::size(input) == 0) { // ignore an empty input, just return empty range?!!
|
||||
r = R{};
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
|
||||
auto r_str = std::views::split(input, _seqDelimiter);
|
||||
auto r_str = std::views::split(input, params.seq_delim);
|
||||
VT val;
|
||||
|
||||
auto it = r.begin();
|
||||
@@ -181,21 +149,21 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
/* MAIN (FALLBACK) TEMPLATED IMPLEMENTATION */
|
||||
|
||||
/* fallback template: basic deserializer */
|
||||
|
||||
template <typename VT>
|
||||
class MccDeserializer : public details::MccDeserializerBase
|
||||
{
|
||||
public:
|
||||
using typename details::MccDeserializerBase::error_t;
|
||||
struct MccDeserializer : MccDeserializerBase {
|
||||
static constexpr std::string_view deserializerName{"MCC-FALLBACK-DESERIALIZER"};
|
||||
|
||||
virtual ~MccDeserializer() = default;
|
||||
|
||||
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input, VT& value)
|
||||
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{})
|
||||
{
|
||||
if constexpr (std::is_arithmetic_v<VT>) {
|
||||
auto v = mcc::utils::numFromStr<VT>(utils::trimSpaces(input));
|
||||
@@ -232,13 +200,13 @@ public:
|
||||
static_assert(std::is_reference_v<el_t> || std::is_const_v<el_t>, "INVALID RANGE ELEMENT TYPE!!!");
|
||||
|
||||
MccDeserializer<el_t> dsr;
|
||||
return deserializingRange<el_t>(dsr, input, value);
|
||||
return deserializingRange<el_t>(dsr, input, value, params);
|
||||
} else if constexpr (traits::mcc_time_duration_c<VT>) {
|
||||
typename VT::rep vd;
|
||||
|
||||
MccDeserializer<typename VT::rep> dsr;
|
||||
|
||||
auto err = dsr(trimSpaces(input), vd);
|
||||
auto err = dsr(trimSpaces(input), vd, params);
|
||||
if (err) {
|
||||
return mcc_deduced_err(err, MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER);
|
||||
}
|
||||
@@ -254,72 +222,147 @@ public:
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* SPECIALIZATION FOR THE SOME CONCEPTS */
|
||||
|
||||
template <mcc_coord_epoch_c VT>
|
||||
struct MccDeserializer<VT> : 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,
|
||||
VT& value,
|
||||
ParamsT const& params = mcc_serialization_params_t{})
|
||||
{
|
||||
bool ok = value.fromCharRange(input);
|
||||
if (!ok) {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename VT>
|
||||
requires(mcc_coord_epoch_c<VT> || (std::ranges::output_range<VT, std::ranges::range_value_t<VT>> &&
|
||||
mcc_coord_epoch_c<std::remove_cv_t<std::ranges::range_value_t<VT>>>))
|
||||
class MccDeserializer<VT> : public details::MccDeserializerBase
|
||||
{
|
||||
public:
|
||||
using typename details::MccDeserializerBase::error_t;
|
||||
requires(!std::is_arithmetic_v<VT> && mcc_angle_c<VT>)
|
||||
struct MccDeserializer<VT> : MccDeserializerBase {
|
||||
static constexpr std::string_view deserializerName{"MCC-ANGLE-DESERIALIZER"};
|
||||
|
||||
virtual ~MccDeserializer() = default;
|
||||
|
||||
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input, VT& value)
|
||||
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{})
|
||||
{
|
||||
if constexpr (mcc_coord_epoch_c<VT>) { // scalar
|
||||
bool ok = value.fromCharRange(input);
|
||||
bool hms = params.angle_format == MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURS;
|
||||
|
||||
auto res = utils::parsAngleString(input, hms);
|
||||
if (res) { // returned angle is in degrees!!!
|
||||
value = res.value() * MCC_DEGRESS_TO_RADS;
|
||||
} else {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <mcc_skypoint_c VT>
|
||||
struct MccDeserializer<VT> : MccDeserializerBase {
|
||||
static constexpr std::string_view deserializerName{"MCC-SKYPOINT-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{})
|
||||
{
|
||||
auto pars = params;
|
||||
|
||||
// valid format: X<elem-delim>Y[<elem-delim>TIME-POINT<elem-delim>PAIR-KIND]
|
||||
// X<elem-delim>Y (assumed RADEC_ICRS and J2000.0 epoch)
|
||||
|
||||
bool empty;
|
||||
|
||||
auto elems = MccDeserializerBase::splitValueIntoElements(input, params, empty);
|
||||
|
||||
if (empty || (elems.size() < 2) || (elems.size() == 3)) {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
MccCoordPairKind pair_kind{MccCoordPairKind::COORDS_KIND_RADEC_ICRS};
|
||||
MccCelestialCoordEpoch epoch; // J2000.0
|
||||
|
||||
MccAngle x, y;
|
||||
MccDeserializer<MccAngle> dsr_ang;
|
||||
|
||||
typename MccDeserializer<MccAngle>::error_t dsr_err;
|
||||
|
||||
if (elems.size() > 3) { // full format
|
||||
// deserialize pair kind string
|
||||
pair_kind = MccCoordStrToPairKind(elems[3]);
|
||||
if (pair_kind == MccCoordPairKind::COORDS_KIND_UNKNOWN) {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
// epoch
|
||||
bool ok = epoch.fromCharRange(elems[2]);
|
||||
if (!ok) {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
} else { // range
|
||||
using value_t = std::remove_cv_t<std::ranges::range_value_t<VT>>;
|
||||
MccDeserializer<value_t> dsr;
|
||||
|
||||
return deserializingRange(dsr, input, value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename VT>
|
||||
requires(!std::is_arithmetic_v<VT> &&
|
||||
(mcc_angle_c<VT> || (std::ranges::output_range<VT, std::ranges::range_value_t<VT>> &&
|
||||
mcc_angle_c<std::remove_cv_t<std::ranges::range_value_t<VT>>>)))
|
||||
class MccDeserializer<VT> : public details::MccDeserializerBase
|
||||
{
|
||||
public:
|
||||
using typename details::MccDeserializerBase::error_t;
|
||||
// deserialize X and Y
|
||||
if (params.coordpair_format == MccSerializedCoordPairFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURDEG) {
|
||||
pars.angle_format = MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_HOURS;
|
||||
} else {
|
||||
pars.angle_format = MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGS;
|
||||
}
|
||||
|
||||
virtual ~MccDeserializer() = default;
|
||||
dsr_err = dsr_ang(elems[0], x, pars);
|
||||
if (dsr_err) {
|
||||
return mcc_deduced_err(dsr_err, MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER);
|
||||
}
|
||||
|
||||
// if hms == true and the input sequence is a sexagesimal string then it interpretates angle as hours:mins:secs
|
||||
// otherwise the input sequence is interpretated as decimal or sexagesimal degrees
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input, VT& value, bool hms = false)
|
||||
{
|
||||
if constexpr (mcc_angle_c<VT>) { // scalar
|
||||
auto res = utils::parsAngleString(input, hms);
|
||||
if (res) { // returned angle is in degrees!!!
|
||||
value = res.value() * MCC_DEGRESS_TO_RADS;
|
||||
} else {
|
||||
pars.angle_format = MccSerializedAngleFormat::MCC_SERIALIZED_FORMAT_SXGM_DEGS;
|
||||
dsr_err = dsr_ang(elems[1], y, pars);
|
||||
if (dsr_err) {
|
||||
return mcc_deduced_err(dsr_err, MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER);
|
||||
}
|
||||
|
||||
switch (pair_kind) {
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_ICRS:
|
||||
value.from(MccSkyRADEC_ICRS{(double)x, (double)y});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_OBS:
|
||||
value.from(MccSkyRADEC_OBS{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_APP:
|
||||
value.from(MccSkyRADEC_APP{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_HADEC_OBS:
|
||||
value.from(MccSkyHADEC_OBS{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_HADEC_APP:
|
||||
value.from(MccSkyHADEC_APP{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_AZZD:
|
||||
value.from(MccSkyAZZD{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_AZALT:
|
||||
value.from(MccSkyAZALT{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_XY:
|
||||
value.from(MccGenXY{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_GENERIC:
|
||||
value.from(MccCoordPair{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_LONLAT:
|
||||
value.from(MccGeoLONLAT{(double)x, (double)y});
|
||||
break;
|
||||
default:
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
} else { // range
|
||||
using value_t = std::remove_cv_t<std::ranges::range_value_t<VT>>;
|
||||
MccDeserializer<value_t> dsr;
|
||||
|
||||
if constexpr (std::invocable<MccDeserializer<value_t>, decltype(input), VT&, bool>) {
|
||||
// it is assumed here, the angle deserializer has the same behavior as the one implemented above
|
||||
// (that is, it can interpret the third argument as a flag "false/true = only
|
||||
// degrees/hour-like")
|
||||
return deserializingRange<value_t>(dsr, input, value, hms);
|
||||
} else {
|
||||
return deserializingRange<value_t>(dsr, input, value);
|
||||
}
|
||||
}
|
||||
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
@@ -327,119 +370,4 @@ public:
|
||||
};
|
||||
|
||||
|
||||
template <typename VT>
|
||||
requires(mcc_skypoint_c<VT> || (std::ranges::output_range<VT, std::ranges::range_value_t<VT>> &&
|
||||
mcc_skypoint_c<std::remove_cv_t<std::ranges::range_value_t<VT>>>))
|
||||
class MccDeserializer<VT> : public details::MccDeserializerBase
|
||||
{
|
||||
public:
|
||||
using typename details::MccDeserializerBase::error_t;
|
||||
|
||||
virtual ~MccDeserializer() = default;
|
||||
|
||||
error_t operator()(traits::mcc_input_char_range auto const& input, VT& value)
|
||||
{
|
||||
if constexpr (mcc_skypoint_c<VT>) { // scalar: X[elem-delim]Y{[elem-delim]TIME-POINT[elem-delim]PAIR-KIND}
|
||||
bool empty; // exactly 2 or >3 elements
|
||||
auto elems = splitAggregateValue(input, empty);
|
||||
|
||||
if (empty || (elems.size() < 2) || (elems.size() == 3)) {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
MccCoordPairKind pair_kind{MccCoordPairKind::COORDS_KIND_RADEC_ICRS};
|
||||
MccCelestialCoordEpoch epoch; // J2000.0
|
||||
|
||||
MccAngle x, y;
|
||||
MccDeserializer<MccAngle> dsr_ang;
|
||||
|
||||
typename MccDeserializer<MccAngle>::error_t dsr_err;
|
||||
|
||||
if (elems.size() >= 4) { // X, Y, TIME-POINT, PAIR-KIND
|
||||
// first, get pair-kind
|
||||
pair_kind = MccCoordStrToPairKind(elems[3]);
|
||||
if (pair_kind == MccCoordPairKind::COORDS_KIND_UNKNOWN) {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
// epoch
|
||||
bool ok = epoch.fromCharRange(elems[2]);
|
||||
if (!ok) {
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (elems.size() >= 2) { // if == 2: just X and Y (if so it is interpretated as RADEC_ICRS)
|
||||
if (MccCoordinatePairToSxgmRep(pair_kind) == MccCoordinatePairRep::MCC_COORDPAIR_REP_SXGM_HOURDEG) {
|
||||
// if input X-angle is in sexagesimal from then interpretate it in hours::mins::secs format
|
||||
if constexpr (std::invocable<MccDeserializer<MccAngle>, decltype(elems[0]), MccAngle&, bool>) {
|
||||
// it is assumed here, the angle deserializer has the same behavior as the one implemented above
|
||||
// (that is, it can interpret the third argument as a flag "false/true = only
|
||||
// degrees/hour-like")
|
||||
dsr_err = dsr_ang(elems[0], x, true);
|
||||
} else {
|
||||
dsr_err = dsr_ang(elems[0], x);
|
||||
}
|
||||
} else {
|
||||
dsr_err = dsr_ang(elems[0], x);
|
||||
}
|
||||
|
||||
if (dsr_err) {
|
||||
return mcc_deduced_err(dsr_err, MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER);
|
||||
}
|
||||
|
||||
dsr_err = dsr_ang(elems[1], y);
|
||||
|
||||
if (dsr_err) {
|
||||
return mcc_deduced_err(dsr_err, MccDeserializerErrorCode::ERROR_UNDERLYING_DESERIALIZER);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch (pair_kind) {
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_ICRS:
|
||||
value.from(MccSkyRADEC_ICRS{(double)x, (double)y});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_OBS:
|
||||
value.from(MccSkyRADEC_OBS{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_RADEC_APP:
|
||||
value.from(MccSkyRADEC_APP{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_HADEC_OBS:
|
||||
value.from(MccSkyHADEC_OBS{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_HADEC_APP:
|
||||
value.from(MccSkyHADEC_APP{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_AZZD:
|
||||
value.from(MccSkyAZZD{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_AZALT:
|
||||
value.from(MccSkyAZALT{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_XY:
|
||||
value.from(MccGenXY{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_GENERIC:
|
||||
value.from(MccCoordPair{(double)x, (double)y, epoch});
|
||||
break;
|
||||
case MccCoordPairKind::COORDS_KIND_LONLAT:
|
||||
value.from(MccGeoLONLAT{(double)x, (double)y});
|
||||
break;
|
||||
default:
|
||||
return MccDeserializerErrorCode::ERROR_INVALID_SERIALIZED_VALUE;
|
||||
}
|
||||
|
||||
} else { // range
|
||||
using value_t = std::remove_cv_t<std::ranges::range_value_t<VT>>;
|
||||
MccDeserializer<value_t> dsr;
|
||||
|
||||
return deserializingRange<value_t>(dsr, input, value);
|
||||
}
|
||||
|
||||
return MccDeserializerErrorCode::ERROR_OK;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mcc::impl
|
||||
|
||||
Reference in New Issue
Block a user