...
This commit is contained in:
parent
096e74c099
commit
41a9c70e70
@ -20,7 +20,8 @@ set(ADC_DEVICE_HEADERS
|
||||
include(GNUInstallDirs)
|
||||
|
||||
add_library(${PROJECT_NAME} INTERFACE ${ADC_COMMON_HEADERS} ${ADC_DEVICE_HEADERS}
|
||||
common/adc_traits.h)
|
||||
common/adc_traits.h
|
||||
common/adc_utils.h)
|
||||
target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_20)
|
||||
# target_link_libraries(${PROJECT_NAME} INTERFACE ASIO::ASIO)
|
||||
target_include_directories(
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <ranges>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
@ -14,6 +15,10 @@
|
||||
namespace adc::traits
|
||||
{
|
||||
|
||||
// range of char/const char
|
||||
template <typename R>
|
||||
concept adc_char_range = std::ranges::range<R> && std::is_same_v<std::remove_cv_t<std::ranges::range_value_t<R>>, char>;
|
||||
|
||||
// deduce returned type of callable
|
||||
template <typename T>
|
||||
using adc_retval_t = std::invoke_result_t<std::remove_cvref_t<T>>;
|
||||
@ -74,7 +79,7 @@ using adc_deduced_type =
|
||||
|
||||
// perfect-forwarding wrapper
|
||||
template <typename T, typename... Ts>
|
||||
auto adc_pf_wrapper(T&& v, Ts&&... vs)
|
||||
constexpr static auto adc_pf_wrapper(T&& v, Ts&&... vs)
|
||||
{
|
||||
return std::tuple<adc_deduced_type<T>, adc_deduced_type<Ts>...>(std::forward<T>(v), std::forward<Ts>(vs)...);
|
||||
}
|
||||
|
||||
129
common/adc_utils.h
Normal file
129
common/adc_utils.h
Normal file
@ -0,0 +1,129 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <charconv>
|
||||
#include <limits>
|
||||
#include <ranges>
|
||||
#include <regex>
|
||||
|
||||
#include "../common/adc_traits.h"
|
||||
|
||||
|
||||
namespace adc::utils
|
||||
{
|
||||
|
||||
bool AdcIsSpace(char in) noexcept
|
||||
{
|
||||
static auto ws = {' ', '\t', '\n', '\v', '\r', '\f'};
|
||||
return std::ranges::any_of(ws, [in](auto p) { return p == in; });
|
||||
};
|
||||
|
||||
|
||||
template <traits::adc_char_range R>
|
||||
auto AdcTrimSpaces(R&& r)
|
||||
{
|
||||
return r | std::views::drop_while(AdcIsSpace) | std::views::reverse | std::views::drop_while(AdcIsSpace) |
|
||||
std::views::reverse;
|
||||
}
|
||||
|
||||
|
||||
template <typename ValueT, traits::adc_char_range R>
|
||||
ValueT AdcFromChars(R&& range)
|
||||
{
|
||||
if constexpr (std::is_arithmetic_v<ValueT>) {
|
||||
ValueT v;
|
||||
|
||||
auto res = std::from_chars(&*range.begin(), &*range.end(), v);
|
||||
|
||||
if (res.ec == std::errc()) {
|
||||
if (res.ptr != &*range.end()) {
|
||||
throw std::invalid_argument(
|
||||
"adc_from_chars: cannot convert char-range to user-type value (invalid argument)");
|
||||
}
|
||||
|
||||
return v;
|
||||
} else if (res.ec == std::errc::invalid_argument) {
|
||||
throw std::invalid_argument(
|
||||
"adc_from_chars: cannot convert char-range to user-type value (invalid argument)");
|
||||
} else if (res.ec == std::errc::result_out_of_range) {
|
||||
throw std::invalid_argument(
|
||||
"adc_from_chars: cannot convert char-range to user-type value (result out of range)");
|
||||
}
|
||||
} else if (std::is_constructible_v<ValueT, std::ranges::iterator_t<R>, std::ranges::iterator_t<R>>) {
|
||||
return ValueT(range.begin(), range.end());
|
||||
} else {
|
||||
throw std::invalid_argument(
|
||||
"adc_from_chars: cannot convert char-range to user-type value (unsupported user-value type)");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* TRIVIAL SERIALIZER/DESERIALIZER */
|
||||
|
||||
static const std::regex AdcIntegerRegex("^ *[+-]?\\d+\\d* *$", std::regex::ECMAScript);
|
||||
static const std::regex AdcRealRegex("^ *[-+]?\\d+\\d*\\.?\\d*([Ee][-+]?\\d+)? *$", std::regex::ECMAScript);
|
||||
|
||||
template <typename VT, typename SerializedT = std::string>
|
||||
static SerializedT AdcTrivialSerializer(VT&& value)
|
||||
{
|
||||
using v_t = std::decay_t<VT>;
|
||||
|
||||
if constexpr (std::is_convertible_v<v_t, SerializedT>) {
|
||||
return static_cast<SerializedT>(std::forward<VT>(value));
|
||||
} else if (std::is_convertible_v<std::string, SerializedT>) {
|
||||
return static_cast<SerializedT>(std::to_string(std::forward<VT>(value)));
|
||||
} else if (traits::adc_char_range<SerializedT>) {
|
||||
auto s = std::to_string(std::forward<VT>(value));
|
||||
return SerializedT(s.begin(), s.end());
|
||||
} else {
|
||||
// throw std::invalid_argument("trivial serializer: cannot serialize value");
|
||||
static_assert(false, "TRIVIAL SERIALIZER: UNSUPPORTED SERIALIZING TYPE!!!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename VT, typename SerializedT = std::string>
|
||||
static VT AdcTrivialDeserializer(SerializedT&& s_value)
|
||||
{
|
||||
static_assert(std::is_convertible_v<SerializedT, std::string> || traits::adc_char_range<SerializedT>,
|
||||
"TRIVIAL DESERIALIZER: UNSUPPORTED TYPE OF SERIALIZED VALUE!!!");
|
||||
|
||||
if constexpr (std::is_arithmetic_v<VT>) {
|
||||
if constexpr (traits::adc_char_range<SerializedT>) {
|
||||
if (std::regex_match(s_value.begin(), s_value.end(), AdcIntegerRegex)) { // integer value
|
||||
return std::stoll({s_value.begin(), s_value.end()});
|
||||
}
|
||||
|
||||
if (std::regex_match(s_value.begin(), s_value.end(), AdcRealRegex)) { // floating-point value
|
||||
return std::stod({s_value.begin(), s_value.end()});
|
||||
}
|
||||
} else { // SerializedT may be converted to std::string
|
||||
if (std::regex_match(s_value, AdcIntegerRegex)) { // integer value
|
||||
return std::stoll(std::forward<SerializedT>(s_value));
|
||||
}
|
||||
|
||||
if (std::regex_match(s_value, AdcRealRegex)) { // floating-point value
|
||||
return std::stod(std::forward<SerializedT>(s_value));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
throw std::invalid_argument("trivial deserializer: unsupported serialized value");
|
||||
|
||||
} else if (std::is_convertible_v<SerializedT, VT>) {
|
||||
return static_cast<VT>(std::forward<SerializedT>(s_value));
|
||||
} else if (std::is_convertible_v<std::string, VT>) { // SerializedT is char range
|
||||
return static_cast<VT>(s_v(s_value.begin(), s_value.end()));
|
||||
}
|
||||
|
||||
throw std::invalid_argument("trivial deserializer: unsupported serialized value");
|
||||
}
|
||||
|
||||
|
||||
template <std::ranges::range OutputR, traits::adc_char_range InputR, traits::adc_char_range DelimR>
|
||||
OutputR AdcRangeFromCharRange(InputR&& input_r, DelimR&& delim_r, size_t max_len = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
OutputR out_r;
|
||||
}
|
||||
|
||||
} // namespace adc::utils
|
||||
@ -107,22 +107,13 @@ protected:
|
||||
|
||||
std::type_index _internalTypeIndex;
|
||||
|
||||
constexpr static std::tuple<char, short, int, long, long long, float, double> _defaultConvTypes{};
|
||||
|
||||
public:
|
||||
// always-true validator
|
||||
constexpr static auto AdcValueHolderDummyValidator = [](const auto&) { return true; };
|
||||
|
||||
/* CONSTRUCTORS AND DESTRUCTOR */
|
||||
|
||||
AdcValueHolder(std::invocable<> auto&& getter,
|
||||
std::invocable<const arg_t<decltype(getter)>&> auto&& setter,
|
||||
std::predicate<const arg_t<decltype(getter)>&> auto&& validator = AdcValueHolderDummyValidator)
|
||||
: _internalTypeIndex(std::type_index(typeid(arg_t<decltype(getter)>)))
|
||||
void init(std::invocable<> auto&& getter,
|
||||
std::invocable<const arg_t<decltype(getter)>&> auto&& setter,
|
||||
std::predicate<const arg_t<decltype(getter)>&> auto&& validator)
|
||||
{
|
||||
using value_t = arg_t<decltype(getter)>;
|
||||
|
||||
static_assert(std::is_same_v<value_t, void>, "THE getter MUST NOT RETURN void type!!!");
|
||||
static_assert(std::is_same_v<value_t, void>, "THE getter MUST NOT RETURN void TYPE!!!");
|
||||
|
||||
using g_t = decltype(getter);
|
||||
_getterWrapper = [wrapper = traits::adc_pf_wrapper(std::forward<g_t>(getter))](std::any& val) {
|
||||
@ -164,6 +155,40 @@ public:
|
||||
_convertToInternal[_internalTypeIndex] = [](auto) {};
|
||||
}
|
||||
|
||||
public:
|
||||
// default trivial types (just arithmetic ones)
|
||||
constexpr static std::tuple<char, short, int, long, long long, float, double> _defaultTrivialConvTypes{};
|
||||
|
||||
// always-true validator
|
||||
constexpr static auto AdcValueHolderDummyValidator = [](const auto&) { return true; };
|
||||
|
||||
/* CONSTRUCTORS AND DESTRUCTOR */
|
||||
|
||||
AdcValueHolder(
|
||||
std::invocable<> auto&& getter,
|
||||
std::invocable<const arg_t<decltype(getter)>&> auto&& setter,
|
||||
std::predicate<const arg_t<decltype(getter)>&> auto&& validator = AdcValueHolder::AdcValueHolderDummyValidator)
|
||||
: _internalTypeIndex(std::type_index(typeid(arg_t<decltype(getter)>)))
|
||||
{
|
||||
init(std::forward<decltype(getter)>(getter), std::forward<decltype(setter)>(setter),
|
||||
std::forward<decltype(validator)>(validator));
|
||||
}
|
||||
|
||||
|
||||
template <typename... Ts>
|
||||
AdcValueHolder(
|
||||
std::invocable<> auto&& getter,
|
||||
std::invocable<const arg_t<decltype(getter)>&> auto&& setter,
|
||||
const std::tuple<Ts...>& trivialConvTypes,
|
||||
std::predicate<const arg_t<decltype(getter)>&> auto&& validator = AdcValueHolder::AdcValueHolderDummyValidator)
|
||||
: AdcValueHolder(std::forward<decltype(getter)>(getter),
|
||||
std::forward<decltype(setter)>(setter),
|
||||
std::forward<decltype(validator)>(validator))
|
||||
{
|
||||
// setup trivially-defined conversion function
|
||||
AdcValueHolder::setupTrivialConvertFunc<arg_t<decltype(getter)>, std::tuple<Ts...>>(this);
|
||||
}
|
||||
|
||||
|
||||
AdcValueHolder(const AdcValueHolder&) = default;
|
||||
AdcValueHolder(AdcValueHolder&&) = default;
|
||||
@ -184,6 +209,38 @@ public:
|
||||
}
|
||||
|
||||
|
||||
AdcValueHolder& resetValueHolder(
|
||||
std::invocable<> auto&& getter,
|
||||
std::invocable<const arg_t<decltype(getter)>&> auto&& setter,
|
||||
std::predicate<const arg_t<decltype(getter)>&> auto&& validator = AdcValueHolderDummyValidator)
|
||||
{
|
||||
_convertFromInternal.clear();
|
||||
_convertToInternal.clear();
|
||||
|
||||
init(std::forward<decltype(getter)>(getter), std::forward<decltype(setter)>(setter),
|
||||
std::forward<decltype(validator)>(validator));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
template <typename... Ts>
|
||||
AdcValueHolder& resetValueHolder(
|
||||
std::invocable<> auto&& getter,
|
||||
std::invocable<const arg_t<decltype(getter)>&> auto&& setter,
|
||||
const std::tuple<Ts...>& trivialConvTypes,
|
||||
std::predicate<const arg_t<decltype(getter)>&> auto&& validator = AdcValueHolderDummyValidator)
|
||||
{
|
||||
resetValueHolder(std::forward<decltype(getter)>(getter), std::forward<decltype(setter)>(setter),
|
||||
std::forward<decltype(validator)>(validator));
|
||||
|
||||
// setup trivially-defined conversion function
|
||||
AdcValueHolder::setupTrivialConvertFunc<arg_t<decltype(getter)>, std::tuple<Ts...>>(this);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
template <typename UT>
|
||||
AdcValueHolder& addConvertFunc(std::invocable<std::any&> auto&& func_to_internal,
|
||||
std::invocable<std::any&> auto&& func_from_internal)
|
||||
@ -202,10 +259,11 @@ public:
|
||||
template <typename UT = void>
|
||||
AdcValueHolder& delConvertFunc()
|
||||
{
|
||||
if constexpr (std::is_same_v<UT, void>) {
|
||||
if constexpr (std::is_same_v<UT, void>) { // delete all conversion functions
|
||||
_convertFromInternal.clear();
|
||||
_convertToInternal.clear();
|
||||
|
||||
// restore conversion functions for internal type
|
||||
_convertFromInternal[_internalTypeIndex] = [](auto) {};
|
||||
_convertToInternal[_internalTypeIndex] = [](auto) {};
|
||||
} else {
|
||||
@ -261,47 +319,35 @@ public:
|
||||
AdcValueHolder& operator=(const AdcValueHolder& other) = default;
|
||||
|
||||
|
||||
template <typename ValueT, typename TupleT = decltype(AdcValueHolder::_defaultConvTypes)>
|
||||
friend AdcValueHolder& setupDefaultConvFunc(AdcValueHolder& holder)
|
||||
{
|
||||
auto t_index = std::type_index(typeid(ValueT));
|
||||
|
||||
if (t_index != holder._internalTypeIndex) {
|
||||
throw std::system_error(AdcValueHolderErrorCode::ERROR_INTERNAL_TYPE_MISMATCH);
|
||||
}
|
||||
|
||||
AdcValueHolder::setupDefaultConvertFunc<ValueT, TupleT>(&holder);
|
||||
|
||||
return holder;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
/* STATIC HELPER METHODS */
|
||||
|
||||
template <typename VT, size_t I, typename TupleT>
|
||||
static void setupDefaultConvertFuncImpl(AdcValueHolder* holder)
|
||||
static void setupTrivialConvertFuncImpl(AdcValueHolder* holder)
|
||||
{
|
||||
if constexpr (I < std::tuple_size_v<TupleT>) {
|
||||
using elem_t = std::tuple_element_t<I, TupleT>;
|
||||
auto t_index = std::type_index(typeid(elem_t));
|
||||
|
||||
holder->_convertToInternal[t_index] = [](std::any& val) {
|
||||
val = std::make_any<VT>(std::any_cast<elem_t>(val));
|
||||
};
|
||||
if constexpr (!std::is_same_v<VT, elem_t>) {
|
||||
auto t_index = std::type_index(typeid(elem_t));
|
||||
|
||||
holder->_convertFromInternal[t_index] = [](std::any& val) {
|
||||
val = std::make_any<elem_t>(std::any_cast<VT>(val));
|
||||
};
|
||||
holder->_convertToInternal[t_index] = [](std::any& val) {
|
||||
val = std::make_any<VT>(std::any_cast<elem_t>(val));
|
||||
};
|
||||
|
||||
AdcValueHolder::setupDefaultConvertFuncImpl<VT, I + 1, TupleT>(holder);
|
||||
holder->_convertFromInternal[t_index] = [](std::any& val) {
|
||||
val = std::make_any<elem_t>(std::any_cast<VT>(val));
|
||||
};
|
||||
}
|
||||
|
||||
AdcValueHolder::setupTrivialConvertFuncImpl<VT, I + 1, TupleT>(holder);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename VT, typename TupleT>
|
||||
static void setupDefaultConvertFunc(AdcValueHolder* holder)
|
||||
static void setupTrivialConvertFunc(AdcValueHolder* holder)
|
||||
{
|
||||
setupDefaultConvertFuncImpl<VT, 0, TupleT>(holder);
|
||||
setupTrivialConvertFuncImpl<VT, 0, TupleT>(holder);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -66,7 +66,7 @@ public:
|
||||
|
||||
_execFuncWrapper = [wrapper = traits::adc_pf_wrapper(std::forward<ExecFuncT>(exec_func)), this]() {
|
||||
auto& exec_func = std::get<0>(wrapper);
|
||||
value_t val = *_commandArgUptr;
|
||||
value_t val = std::any_cast<value_t>(*_commandArgUptr);
|
||||
exec_func(val);
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user