#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 = arg_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 */ AdcValueHolder(std::invocable<> auto&& getter, std::invocable&> auto&& setter, std::predicate&> auto&& validator) : _internalTypeIndex(std::type_index(typeid(arg_t))) { init(std::forward(getter), std::forward(setter), std::forward(validator)); } // NOTE: due to using of concepts one cannot use of default value for validator callable!!! AdcValueHolder(std::invocable<> auto&& getter, std::invocable&> auto&& setter) : AdcValueHolder(std::forward(getter), std::forward(setter), AdcValueHolder::AdcValueHolderDummyValidator>) { } 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()}; } AdcValueHolder& resetValueHolder(std::invocable<> auto&& getter, std::invocable&> auto&& setter, std::predicate&> auto&& validator = AdcValueHolder::AdcValueHolderDummyValidator>) { _convertFromInternal.clear(); _convertToInternal.clear(); init(std::forward(getter), std::forward(setter), std::forward(validator)); return *this; } AdcValueHolder& resetValueHolder(std::invocable<> auto&& getter, std::invocable&> auto&& setter) { return resetValueHolder(std::forward(getter), std::forward(setter), AdcValueHolder::AdcValueHolderDummyValidator>); } 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 */ AdcValueHolder make_arith_valueholder(std::invocable<> auto&& getter, std::invocable&> auto&& setter, std::predicate&> auto&& validator) { 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); } AdcValueHolder make_arith_valueholder(std::invocable<> auto&& getter, std::invocable&> auto&& setter) { return make_arith_valueholder(std::forward(getter), std::forward(setter), AdcValueHolder::AdcValueHolderDummyValidator>); } } // namespace adc