451 lines
15 KiB
C++
451 lines
15 KiB
C++
#pragma once
|
|
|
|
/*
|
|
|
|
ABSTRACT DEVICE COMPONENTS LIBRARY
|
|
|
|
*/
|
|
|
|
|
|
#include <any>
|
|
#include <concepts>
|
|
#include <functional>
|
|
#include <map>
|
|
#include <ranges>
|
|
#include <system_error>
|
|
#include <typeindex>
|
|
|
|
#include "adc_traits.h"
|
|
|
|
namespace adc
|
|
{
|
|
|
|
// error codes
|
|
enum class AdcValueHolderErrorCode : int {
|
|
ERROR_OK,
|
|
ERROR_NO_CONV_FUNC,
|
|
ERROR_INTERNAL_TYPE_MISMATCH,
|
|
ERROR_VALUE_IS_NOT_VALID
|
|
};
|
|
|
|
} // namespace adc
|
|
|
|
|
|
namespace std
|
|
{
|
|
|
|
template <>
|
|
class is_error_code_enum<adc::AdcValueHolderErrorCode> : public true_type
|
|
{
|
|
};
|
|
|
|
} // namespace std
|
|
|
|
|
|
namespace adc
|
|
{
|
|
|
|
|
|
|
|
// error category
|
|
struct AdcValueHolderErrorCategory : public std::error_category {
|
|
AdcValueHolderErrorCategory() : std::error_category() {}
|
|
|
|
const char* name() const noexcept { return "DEVA_DEVICE_ATTRIBUTE"; }
|
|
|
|
std::string message(int ec) const
|
|
{
|
|
AdcValueHolderErrorCode err = static_cast<AdcValueHolderErrorCode>(ec);
|
|
|
|
switch (err) {
|
|
case AdcValueHolderErrorCode::ERROR_OK:
|
|
return "OK";
|
|
case AdcValueHolderErrorCode::ERROR_NO_CONV_FUNC:
|
|
return "conversion function is not defined";
|
|
case AdcValueHolderErrorCode::ERROR_INTERNAL_TYPE_MISMATCH:
|
|
return "try to setup default conversion function for invalid type (internal type mismatch)";
|
|
case AdcValueHolderErrorCode::ERROR_VALUE_IS_NOT_VALID:
|
|
return "user value is not valid";
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
static const AdcValueHolderErrorCategory& get()
|
|
{
|
|
static const AdcValueHolderErrorCategory constInst;
|
|
return constInst;
|
|
}
|
|
};
|
|
|
|
|
|
inline std::error_code make_error_code(AdcValueHolderErrorCode ec)
|
|
{
|
|
return std::error_code(static_cast<int>(ec), AdcValueHolderErrorCategory::get());
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
GENERAL-PURPOSE VALUE HOLDER CLASS WITH OPTIONAL VALIDATOR
|
|
|
|
*/
|
|
|
|
|
|
class AdcValueHolder
|
|
{
|
|
protected:
|
|
template <typename T>
|
|
using arg_t = typename traits::adc_func_traits<std::remove_reference_t<T>>::ret_t;
|
|
|
|
std::function<void(std::any&)> _getterWrapper;
|
|
std::function<void(const std::any&)> _setterWrapper;
|
|
|
|
std::map<std::type_index, std::function<void(std::any&)>> _convertToInternal;
|
|
std::map<std::type_index, std::function<void(std::any&)>> _convertFromInternal;
|
|
|
|
std::type_index _internalTypeIndex;
|
|
|
|
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!!!");
|
|
|
|
using g_t = decltype(getter);
|
|
_getterWrapper = [wrapper = traits::adc_pf_wrapper(std::forward<g_t>(getter))](std::any& val) {
|
|
auto& getter = std::get<0>(wrapper);
|
|
val = getter();
|
|
};
|
|
|
|
|
|
using vld_t = decltype(validator);
|
|
using s_t = decltype(setter);
|
|
|
|
if constexpr (std::is_same_v<vld_t, decltype(AdcValueHolderDummyValidator<value_t>)>) { // no validation
|
|
_setterWrapper = [wrapper = traits::adc_pf_wrapper(std::forward<s_t>(setter)), this](const std::any& val) {
|
|
auto& setter = std::get<0>(wrapper);
|
|
|
|
setter(std::any_cast<value_t>(val));
|
|
};
|
|
} else {
|
|
_setterWrapper = [wrapper =
|
|
traits::adc_pf_wrapper(std::forward<s_t>(setter), std::forward<vld_t>(validator)),
|
|
this](const std::any& val) {
|
|
auto& setter = std::get<0>(wrapper);
|
|
auto& validator = std::get<1>(wrapper);
|
|
|
|
auto v = std::any_cast<value_t>(val);
|
|
|
|
if (validator(v)) {
|
|
setter(v);
|
|
} else {
|
|
throw std::system_error(AdcValueHolderErrorCode::ERROR_VALUE_IS_NOT_VALID);
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
// By default no conversion will be made if user value of internal type is given.
|
|
// But such a conversion may be defined explicitly by calling addConvertFunc method
|
|
_convertFromInternal[_internalTypeIndex] = [](auto) {};
|
|
_convertToInternal[_internalTypeIndex] = [](auto) {};
|
|
}
|
|
|
|
public:
|
|
// default trivial types (just arithmetic ones)
|
|
constexpr static std::tuple<bool,
|
|
char,
|
|
short,
|
|
int,
|
|
long,
|
|
long long,
|
|
unsigned char,
|
|
unsigned short,
|
|
unsigned int,
|
|
unsigned long,
|
|
unsigned long long,
|
|
float,
|
|
double,
|
|
long double>
|
|
_defaultTrivialConvTypes{};
|
|
|
|
// always-true validator
|
|
// constexpr static auto AdcValueHolderDummyValidator = [](const auto&) { return true; };
|
|
template <typename VT>
|
|
constexpr static bool AdcValueHolderDummyValidator(const VT&)
|
|
{
|
|
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)
|
|
: _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));
|
|
}
|
|
|
|
|
|
// NOTE: due to using of concepts one cannot use of default value for validator callable!!!
|
|
AdcValueHolder(std::invocable<> auto&& getter, std::invocable<const arg_t<decltype(getter)>&> auto&& setter)
|
|
: AdcValueHolder(std::forward<decltype(getter)>(getter),
|
|
std::forward<decltype(setter)>(setter),
|
|
AdcValueHolder::AdcValueHolderDummyValidator<traits::adc_retval_t<decltype(getter)>>)
|
|
{
|
|
}
|
|
|
|
|
|
template <typename... Ts>
|
|
AdcValueHolder(std::invocable<> auto&& getter,
|
|
std::invocable<const arg_t<decltype(getter)>&> auto&& setter,
|
|
std::predicate<const arg_t<decltype(getter)>&> auto&& validator,
|
|
const std::tuple<Ts...>& /* tuple-of-trivially-converting-types */)
|
|
: 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);
|
|
}
|
|
|
|
|
|
template <typename... Ts>
|
|
AdcValueHolder(std::invocable<> auto&& getter,
|
|
std::invocable<const arg_t<decltype(getter)>&> auto&& setter,
|
|
const std::tuple<Ts...>& t /* tuple-of-trivially-converting-types */)
|
|
: AdcValueHolder(std::forward<decltype(getter)>(getter),
|
|
std::forward<decltype(setter)>(setter),
|
|
AdcValueHolder::AdcValueHolderDummyValidator<traits::adc_retval_t<decltype(getter)>>,
|
|
t)
|
|
{
|
|
}
|
|
|
|
|
|
AdcValueHolder(const AdcValueHolder&) = default;
|
|
AdcValueHolder(AdcValueHolder&&) = default;
|
|
|
|
virtual ~AdcValueHolder() = default;
|
|
|
|
|
|
/* PUBLIC METHODS */
|
|
|
|
|
|
std::type_index valueTypeIndex() const { return _internalTypeIndex; }
|
|
|
|
|
|
std::vector<std::type_index> convTypeIndices()
|
|
{
|
|
auto kv = std::views::keys(_convertFromInternal);
|
|
return {kv.begin(), kv.end()};
|
|
}
|
|
|
|
|
|
AdcValueHolder& resetValueHolder(std::invocable<> auto&& getter,
|
|
std::invocable<const arg_t<decltype(getter)>&> auto&& setter,
|
|
std::predicate<const arg_t<decltype(getter)>&> auto&& validator =
|
|
AdcValueHolder::AdcValueHolderDummyValidator<arg_t<decltype(getter)>>)
|
|
{
|
|
_convertFromInternal.clear();
|
|
_convertToInternal.clear();
|
|
|
|
init(std::forward<decltype(getter)>(getter), std::forward<decltype(setter)>(setter),
|
|
std::forward<decltype(validator)>(validator));
|
|
|
|
return *this;
|
|
}
|
|
|
|
|
|
AdcValueHolder& resetValueHolder(std::invocable<> auto&& getter,
|
|
std::invocable<const arg_t<decltype(getter)>&> auto&& setter)
|
|
{
|
|
return resetValueHolder(std::forward<decltype(getter)>(getter), std::forward<decltype(setter)>(setter),
|
|
AdcValueHolder::AdcValueHolderDummyValidator<traits::adc_retval_t<decltype(getter)>>);
|
|
}
|
|
|
|
|
|
template <typename... Ts>
|
|
AdcValueHolder& resetValueHolder(std::invocable<> auto&& getter,
|
|
std::invocable<const arg_t<decltype(getter)>&> auto&& setter,
|
|
std::predicate<const arg_t<decltype(getter)>&> auto&& validator,
|
|
const std::tuple<Ts...>& /* tuple-of-trivially-converting-types */)
|
|
{
|
|
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... Ts>
|
|
AdcValueHolder& resetValueHolder(std::invocable<> auto&& getter,
|
|
std::invocable<const arg_t<decltype(getter)>&> auto&& setter,
|
|
const std::tuple<Ts...>& t /* tuple-of-trivially-converting-types */)
|
|
{
|
|
return resetValueHolder(std::forward<decltype(getter)>(getter), std::forward<decltype(setter)>(setter),
|
|
AdcValueHolder::AdcValueHolderDummyValidator<traits::adc_retval_t<decltype(getter)>>,
|
|
t);
|
|
}
|
|
|
|
|
|
template <typename UT>
|
|
AdcValueHolder& addConvertFunc(std::invocable<std::any&> auto&& func_to_internal,
|
|
std::invocable<std::any&> auto&& func_from_internal)
|
|
{
|
|
static_assert(!std::is_same_v<UT, void>, "void IS NOT VALID TYPE!!!");
|
|
|
|
auto t_index = std::type_index(typeid(UT));
|
|
|
|
_convertToInternal[t_index] = std::forward<decltype(func_to_internal)>(func_to_internal);
|
|
_convertFromInternal[t_index] = std::forward<decltype(func_from_internal)>(func_from_internal);
|
|
|
|
return *this;
|
|
}
|
|
|
|
|
|
template <typename UT = void>
|
|
AdcValueHolder& delConvertFunc()
|
|
{
|
|
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 {
|
|
auto t_index = std::type_index(typeid(UT));
|
|
|
|
_convertFromInternal.erase(t_index);
|
|
_convertToInternal.erase(t_index);
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
|
|
template <typename UT>
|
|
operator UT()
|
|
{
|
|
using v_t = std::remove_reference_t<UT>;
|
|
using val_t = std::conditional_t<std::is_array_v<v_t>, std::add_pointer_t<std::remove_extent_t<v_t>>, v_t>;
|
|
|
|
std::any val;
|
|
|
|
// auto t_index = std::type_index(typeid(UT));
|
|
auto t_index = std::type_index(typeid(val_t));
|
|
auto it = _convertFromInternal.find(t_index);
|
|
|
|
if (it == _convertFromInternal.end()) {
|
|
throw std::system_error(AdcValueHolderErrorCode::ERROR_NO_CONV_FUNC);
|
|
}
|
|
|
|
_getterWrapper(val);
|
|
it->second(val); // call conversion function
|
|
|
|
// return std::any_cast<UT>(val);
|
|
return std::any_cast<val_t>(val);
|
|
}
|
|
|
|
template <typename UT>
|
|
AdcValueHolder& operator=(UT&& value)
|
|
{
|
|
using v_t = std::remove_reference_t<UT>;
|
|
using val_t = std::conditional_t<std::is_array_v<v_t>, std::add_pointer_t<std::remove_extent_t<v_t>>, v_t>;
|
|
|
|
// std::any val = std::make_any<UT>(value);
|
|
std::any val = std::make_any<val_t>(value);
|
|
|
|
// auto t_index = std::type_index(typeid(UT));
|
|
auto t_index = std::type_index(typeid(val_t));
|
|
auto it = _convertToInternal.find(t_index);
|
|
|
|
if (it == _convertToInternal.end()) {
|
|
throw std::system_error(AdcValueHolderErrorCode::ERROR_NO_CONV_FUNC);
|
|
}
|
|
|
|
it->second(val); // call conversion function
|
|
|
|
_setterWrapper(val);
|
|
|
|
return *this;
|
|
}
|
|
|
|
|
|
AdcValueHolder& operator=(AdcValueHolder&& other) = default;
|
|
AdcValueHolder& operator=(const AdcValueHolder& other) = default;
|
|
|
|
|
|
protected:
|
|
/* STATIC HELPER METHODS */
|
|
|
|
template <typename VT, size_t I, typename TupleT>
|
|
static void setupTrivialConvertFuncImpl(AdcValueHolder* holder)
|
|
{
|
|
if constexpr (I < std::tuple_size_v<TupleT>) {
|
|
using elem_t = std::tuple_element_t<I, TupleT>;
|
|
|
|
if constexpr (!std::is_same_v<VT, elem_t>) {
|
|
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));
|
|
};
|
|
|
|
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 setupTrivialConvertFunc(AdcValueHolder* holder)
|
|
{
|
|
setupTrivialConvertFuncImpl<VT, 0, TupleT>(holder);
|
|
}
|
|
};
|
|
|
|
|
|
/*
|
|
factory functions
|
|
|
|
*/
|
|
|
|
AdcValueHolder make_arith_valueholder(std::invocable<> auto&& getter,
|
|
std::invocable<const traits::adc_retval_t<decltype(getter)>&> auto&& setter,
|
|
std::predicate<const traits::adc_retval_t<decltype(getter)>&> auto&& validator)
|
|
{
|
|
using val_t = traits::adc_retval_t<decltype(getter)>;
|
|
|
|
static_assert(std::predicate<decltype(validator), const traits::adc_retval_t<decltype(getter)>&>,
|
|
"INVALID VALIDATOR TYPE!!!");
|
|
|
|
static_assert(std::is_arithmetic_v<val_t>, "GETTER MUST RETURN AN ARITHMETIC TYPE VALUE!!!");
|
|
|
|
return AdcValueHolder(std::forward<decltype(getter)>(getter), std::forward<decltype(setter)>(setter),
|
|
std::forward<decltype(validator)>(validator), AdcValueHolder::_defaultTrivialConvTypes);
|
|
}
|
|
|
|
|
|
AdcValueHolder make_arith_valueholder(std::invocable<> auto&& getter,
|
|
std::invocable<const traits::adc_retval_t<decltype(getter)>&> auto&& setter)
|
|
{
|
|
return make_arith_valueholder(std::forward<decltype(getter)>(getter), std::forward<decltype(setter)>(setter),
|
|
AdcValueHolder::AdcValueHolderDummyValidator<traits::adc_retval_t<decltype(getter)>>);
|
|
}
|
|
|
|
|
|
} // namespace adc
|