#pragma once /* ABSTRACT DEVICE COMPONENTS LIBRARY */ #include #include #include #include #include #include #include #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 : 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(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(ec), AdcValueHolderErrorCategory::get()); } /* GENERAL-PURPOSE VALUE HOLDER CLASS WITH OPTIONAL VALIDATOR */ class AdcValueHolder { protected: // template // using arg_t = typename traits::adc_func_traits>::ret_t; std::function _getterWrapper; std::function _setterWrapper; std::map> _convertToInternal; std::map> _convertFromInternal; std::type_index _internalTypeIndex; void init(std::invocable<> auto&& getter, std::invocable&> auto&& setter, std::predicate&> auto&& validator) { using value_t = traits::adc_retval_t; static_assert(!std::is_same_v, "THE getter MUST NOT RETURN void TYPE!!!"); using g_t = decltype(getter); _getterWrapper = [wrapper = traits::adc_pf_wrapper(std::forward(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)>) { // no validation _setterWrapper = [wrapper = traits::adc_pf_wrapper(std::forward(setter)), this](const std::any& val) { auto& setter = std::get<0>(wrapper); setter(std::any_cast(val)); }; } else { _setterWrapper = [wrapper = traits::adc_pf_wrapper(std::forward(setter), std::forward(validator)), this](const std::any& val) { auto& setter = std::get<0>(wrapper); auto& validator = std::get<1>(wrapper); auto v = std::any_cast(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 _defaultTrivialConvTypes{}; // always-true validator // constexpr static auto AdcValueHolderDummyValidator = [](const auto&) { return true; }; template constexpr static bool AdcValueHolderDummyValidator(const VT&) { return true; }; /* CONSTRUCTORS AND DESTRUCTOR */ template , typename VT = decltype(AdcValueHolder::AdcValueHolderDummyValidator)> AdcValueHolder(GT&& getter, std::invocable auto&& setter, VT&& validator = AdcValueHolder::AdcValueHolderDummyValidator) requires std::invocable && std::predicate : _internalTypeIndex(std::type_index(typeid(VALT))) { init(std::forward(getter), std::forward(setter), std::forward(validator)); } template AdcValueHolder(std::invocable<> auto&& getter, std::invocable&> auto&& setter, std::predicate&> auto&& validator, const std::tuple& /* tuple-of-trivially-converting-types */) : AdcValueHolder(std::forward(getter), std::forward(setter), std::forward(validator)) { // setup trivially-defined conversion function AdcValueHolder::setupTrivialConvertFunc, std::tuple>(this); } template AdcValueHolder(std::invocable<> auto&& getter, std::invocable&> auto&& setter, const std::tuple& t /* tuple-of-trivially-converting-types */) : AdcValueHolder(std::forward(getter), std::forward(setter), AdcValueHolder::AdcValueHolderDummyValidator>, t) { } AdcValueHolder(const AdcValueHolder&) = default; AdcValueHolder(AdcValueHolder&&) = default; virtual ~AdcValueHolder() = default; /* PUBLIC METHODS */ std::type_index valueTypeIndex() const { return _internalTypeIndex; } std::vector convTypeIndices() { auto kv = std::views::keys(_convertFromInternal); return {kv.begin(), kv.end()}; } template , typename VT = decltype(AdcValueHolder::AdcValueHolderDummyValidator)> AdcValueHolder& resetValueHolder(GT&& getter, std::invocable auto&& setter, VT&& validator = AdcValueHolder::AdcValueHolderDummyValidator) requires std::invocable && std::predicate { _convertFromInternal.clear(); _convertToInternal.clear(); init(std::forward(getter), std::forward(setter), std::forward(validator)); return *this; } template AdcValueHolder& resetValueHolder(std::invocable<> auto&& getter, std::invocable&> auto&& setter, std::predicate&> auto&& validator, const std::tuple& /* tuple-of-trivially-converting-types */) { resetValueHolder(std::forward(getter), std::forward(setter), std::forward(validator)); // setup trivially-defined conversion function AdcValueHolder::setupTrivialConvertFunc, std::tuple>(this); return *this; } template AdcValueHolder& resetValueHolder(std::invocable<> auto&& getter, std::invocable&> auto&& setter, const std::tuple& t /* tuple-of-trivially-converting-types */) { return resetValueHolder(std::forward(getter), std::forward(setter), AdcValueHolder::AdcValueHolderDummyValidator>, t); } template AdcValueHolder& addConvertFunc(std::invocable auto&& func_to_internal, std::invocable auto&& func_from_internal) { static_assert(!std::is_same_v, "void IS NOT VALID TYPE!!!"); auto t_index = std::type_index(typeid(UT)); _convertToInternal[t_index] = std::forward(func_to_internal); _convertFromInternal[t_index] = std::forward(func_from_internal); return *this; } template AdcValueHolder& delConvertFunc() { if constexpr (std::is_same_v) { // 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 operator UT() { using v_t = std::remove_reference_t; using val_t = std::conditional_t, std::add_pointer_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(val); return std::any_cast(val); } template AdcValueHolder& operator=(UT&& value) { using v_t = std::remove_reference_t; using val_t = std::conditional_t, std::add_pointer_t>, v_t>; // std::any val = std::make_any(value); std::any val = std::make_any(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 static void setupTrivialConvertFuncImpl(AdcValueHolder* holder) { if constexpr (I < std::tuple_size_v) { using elem_t = std::tuple_element_t; if constexpr (!std::is_same_v) { auto t_index = std::type_index(typeid(elem_t)); holder->_convertToInternal[t_index] = [](std::any& val) { val = std::make_any(std::any_cast(val)); }; holder->_convertFromInternal[t_index] = [](std::any& val) { val = std::make_any(std::any_cast(val)); }; } AdcValueHolder::setupTrivialConvertFuncImpl(holder); } } template static void setupTrivialConvertFunc(AdcValueHolder* holder) { setupTrivialConvertFuncImpl(holder); } }; /* factory functions */ template , typename VT = decltype(AdcValueHolder::AdcValueHolderDummyValidator)> AdcValueHolder make_arith_valueholder(GT&& getter, std::invocable auto&& setter, VT&& validator = AdcValueHolder::AdcValueHolderDummyValidator) requires std::invocable && std::predicate { using val_t = traits::adc_retval_t; // static_assert(std::predicate&>, // "INVALID VALIDATOR TYPE!!!"); static_assert(std::is_arithmetic_v, "GETTER MUST RETURN AN ARITHMETIC TYPE VALUE!!!"); return AdcValueHolder(std::forward(getter), std::forward(setter), std::forward(validator), AdcValueHolder::_defaultTrivialConvTypes); } /* */ template class AdcSerializingValueHolder : public AdcValueHolder { protected: std::function _serializerWrapper = []() { }; std::function _deserializerWrapper; template void init(GT&& getter, ST&& setter, VT&& validator, SRT&& serializer, DSRT&& deserializer) { _serializerWrapper = [wrapper = traits::adc_pf_wrapper(std::forward(getter), std::forward(serializer))]() { auto& getter = std::get<0>(wrapper); auto& serializer = std::get<1>(wrapper); auto val = getter(); return serializer(val); }; using v_t = traits::adc_retval_t; _serializerWrapper = [wrapper = traits::adc_pf_wrapper(std::forward(setter), std::forward(validator), std::forward(deserializer))](const SerializedT& sval) { auto& setter = std::get<0>(wrapper); auto& validator = std::get<1>(wrapper); auto& deserializer = std::get<2>(wrapper); v_t val = deserializer(sval); if (validator(val)) { setter(val); } else { throw std::system_error(AdcValueHolderErrorCode::ERROR_VALUE_IS_NOT_VALID); } }; } public: using AdcValueHolder::AdcValueHolder; virtual ~AdcSerializingValueHolder() = default; }; } // namespace adc