#pragma once /* ABSTRACT DEVICE COMPONENTS LIBRARY */ #include #include #include "../common/adc_traits.h" #include "../common/adc_utils.h" // #include "../common/adc_value.h" namespace adc { namespace constants { static constexpr std::tuple AdcDefaultTrivialConvTypes{}; } // namespace constants namespace traits { /* concepts */ // attribute setter concept template concept adc_attr_getter_c = std::is_null_pointer_v || (traits::adc_func_traits::arity == 0 && !std::same_as, void>); // attribute setter concept template concept adc_attr_setter_c = std::is_null_pointer_v || (traits::adc_func_traits::arity == 1); // internal-to-user and user-to-internal type conversional function concept template concept adc_attr_convfunc_c = std::is_null_pointer_v || (traits::adc_func_traits::arity == 1 && !std::same_as, void>); // deduce attribute type from getter and setter functions signatures template using attr_value_t = std::decay_t< std::conditional_t, std::conditional_t, std::nullptr_t, traits::adc_func_arg1_t>, traits::adc_retval_t>>; // deduce attribute internal type from conversional functions signatures template using attr_internal_t = std::decay_t, std::conditional_t, std::nullptr_t, traits::adc_retval_t>, traits::adc_retval_t>>; // deduce user-defined type from conversional functions signatures template using attr_user_t = std::decay_t, std::conditional_t, std::nullptr_t, traits::adc_retval_t>, traits::adc_retval_t>>; // attribute serializer function concept template concept adc_serializer_c = std::is_null_pointer_v || (std::invocable && !std::same_as>); // attribute deserializer function concept template concept adc_deserializer_c = std::is_null_pointer_v || (traits::adc_func_traits::arity == 1 && std::convertible_to, VT>); template using adc_attr_serialized_t = std::decay_t< std::conditional_t, std::conditional_t, std::nullptr_t, traits::adc_func_arg1_t>, traits::adc_retval_t>>; } // namespace traits // error codes enum class AdcDeviceAttributeErrorCode : int { ERROR_OK, ERROR_NO_CONV_FUNC, ERROR_INTERNAL_TYPE_MISMATCH, ERROR_READ_ONLY, ERROR_WRITE_ONLY, ERROR_INVALID_SERIALIZED_TYPE, ERROR_NO_SERIALIZER, ERROR_NO_DESERIALIZER }; } // namespace adc namespace std { template <> class is_error_code_enum : public true_type { }; } // namespace std namespace adc { // error category struct AdcDeviceAttributeErrorCategory : public std::error_category { AdcDeviceAttributeErrorCategory() : std::error_category() {} const char* name() const noexcept { return "ADC_DEVICE_ATTRIBUTE_CATEGORY"; } std::string message(int ec) const { AdcDeviceAttributeErrorCode err = static_cast(ec); switch (err) { case AdcDeviceAttributeErrorCode::ERROR_OK: return "OK"; case AdcDeviceAttributeErrorCode::ERROR_NO_CONV_FUNC: return "conversion function is not defined"; case AdcDeviceAttributeErrorCode::ERROR_INTERNAL_TYPE_MISMATCH: return "try to setup default conversion function for invalid type (internal type mismatch)"; case AdcDeviceAttributeErrorCode::ERROR_READ_ONLY: return "device attribute is read-only"; case AdcDeviceAttributeErrorCode::ERROR_WRITE_ONLY: return "device attribute is write-only"; case AdcDeviceAttributeErrorCode::ERROR_INVALID_SERIALIZED_TYPE: return "invalid user-passed serialized type"; case AdcDeviceAttributeErrorCode::ERROR_NO_SERIALIZER: return "serializing function was not defined"; case AdcDeviceAttributeErrorCode::ERROR_NO_DESERIALIZER: return "deserializing function was not defined"; default: return "UNKNOWN"; } } static const AdcDeviceAttributeErrorCategory& get() { static const AdcDeviceAttributeErrorCategory constInst; return constInst; } }; inline std::error_code make_error_code(AdcDeviceAttributeErrorCode ec) { return std::error_code(static_cast(ec), AdcDeviceAttributeErrorCategory::get()); } template > class AdcDeviceAttribute { static_assert(!std::is_null_pointer_v, "Deduced serialized type must not be std::nullptr_t!!!"); protected: template using ret_value_t = std::decay_t>; template inline static std::unordered_map> _getterFunc{}; template inline static std::unordered_map> _setterFunc{}; std::function _serializerFunc; std::function _deserializerFunc; // static inline std::vector> _clearFunc{}; std::vector> _clearFunc{}; // static inline std::vector> _copyFunc{}; // static inline std::vector> _moveFunc{}; std::vector> _copyFunc{}; std::vector> _moveFunc{}; public: typedef IdentT ident_t; typedef SerializedT serialized_t; enum AccessType { ReadOnly, WriteOnly, ReadWrite }; /* CONSTRUCTORS AND DESTRUCTOR */ template , traits::adc_serializer_c SRT = decltype(utils::AdcDefaultValueConverter<>::serialize), traits::adc_deserializer_c DSRT = decltype(utils::AdcDefaultValueConverter<>::deserialize)> AdcDeviceAttribute(const IdentT& ident, GT&& getter, ST&& setter, SRT&& serializer = utils::AdcDefaultValueConverter<>::serialize, DSRT&& deserializer = utils::AdcDefaultValueConverter<>::deserialize) : _ident(ident), _accessType(AdcDeviceAttribute::ReadWrite) { static_assert(!std::is_null_pointer_v, "Getter and Setter can not be nullptr simultaneously!!!"); _getterFunc.emplace(this, std::forward(getter)); _setterFunc.emplace(this, std::forward(setter)); if constexpr (std::is_null_pointer_v) { _accessType = AdcDeviceAttribute::WriteOnly; } if constexpr (std::is_null_pointer_v) { _accessType = AdcDeviceAttribute::ReadOnly; } if constexpr (!std::is_null_pointer_v && !std::is_null_pointer_v) { auto& getter_func = _getterFunc[this]; _serializerFunc = [getter_func, wrapper = traits::adc_pf_wrapper(std::forward(serializer)), this]() { auto& serializer = std::get<0>(wrapper); // auto val = _getterFunc[this](); auto val = getter_func(); return serializer(val); }; } if constexpr (!std::is_null_pointer_v && !std::is_null_pointer_v) { auto& setter_func = _setterFunc[this]; _deserializerFunc = [setter_func, wrapper = traits::adc_pf_wrapper(std::forward(deserializer)), this](const SerializedT& sval) { auto& deserializer = std::get<0>(wrapper); ValueT val = deserializer(sval); // _setterFunc[this](val); setter_func(val); }; } _clearFunc.emplace_back([](AdcDeviceAttribute* inst) { _getterFunc.erase(inst); _setterFunc.erase(inst); }); // copy instance function _copyFunc.emplace_back([](const AdcDeviceAttribute* from, AdcDeviceAttribute* to) { _getterFunc.emplace(to, _getterFunc[from]); _setterFunc.emplace(to, _setterFunc[from]); }); // move instance function _moveFunc.emplace_back([](AdcDeviceAttribute* from, AdcDeviceAttribute* to) { _getterFunc.emplace(to, std::move(_getterFunc[from])); _setterFunc.emplace(to, std::move(_setterFunc[from])); }); } template , traits::adc_serializer_c SRT = decltype(utils::AdcDefaultValueConverter<>::serialize), traits::adc_deserializer_c DSRT = decltype(utils::AdcDefaultValueConverter<>::deserialize)> AdcDeviceAttribute(const IdentT& ident, TupleT&&, GT&& getter, ST&& setter, SRT&& serializer = utils::AdcDefaultValueConverter<>::serialize, DSRT&& deserializer = utils::AdcDefaultValueConverter<>::deserialize) : AdcDeviceAttribute(ident, std::forward(getter), std::forward(setter), std::forward(serializer), std::forward(deserializer)) { static_assert(!std::is_null_pointer_v, "Getter and Setter can not be nullptr simultaneously!!!"); AdcDeviceAttribute::setupTrivialConvertFunc>(); } // read-only attribute constructor template , traits::adc_serializer_c SRT = decltype(utils::AdcDefaultValueConverter<>::serialize)> AdcDeviceAttribute(const IdentT& ident, GT&& getter, SRT&& serializer = utils::AdcDefaultValueConverter<>::serialize) : AdcDeviceAttribute(ident, std::forward(getter), nullptr, std::forward(serializer), nullptr) { } template , traits::adc_serializer_c SRT = decltype(utils::AdcDefaultValueConverter<>::serialize)> AdcDeviceAttribute(const IdentT& ident, TupleT&&, GT&& getter, SRT&& serializer = utils::AdcDefaultValueConverter<>::serialize) : AdcDeviceAttribute(ident, TupleT{}, std::forward(getter), nullptr, std::forward(serializer), nullptr) { } // write-only attribute constructor template >, typename DSRT = decltype(utils::AdcDefaultValueConverter<>::deserialize)> AdcDeviceAttribute(const IdentT& ident, ST&& setter, DSRT&& deserializer = utils::AdcDefaultValueConverter<>::deserialize) : AdcDeviceAttribute(ident, nullptr, std::forward(setter), nullptr, std::forward(deserializer)) { } template >, typename DSRT = decltype(utils::AdcDefaultValueConverter<>::deserialize)> AdcDeviceAttribute(const IdentT& ident, TupleT&&, ST&& setter, DSRT&& deserializer = utils::AdcDefaultValueConverter<>::deserialize) : AdcDeviceAttribute(ident, TupleT{}, nullptr, std::forward(setter), nullptr, std::forward(deserializer)) { } AdcDeviceAttribute(const AdcDeviceAttribute& other) { if (&other != this) { // for (auto& fn : _copyFunc) { for (auto& fn : other._copyFunc) { fn(&other, this); } _copyFunc = other._copyFunc; _moveFunc = other._moveFunc; _clearFunc = other._clearFunc; _ident = other._ident; _accessType = other._accessType; _serializerFunc = other._serializerFunc; _deserializerFunc = other._deserializerFunc; } } AdcDeviceAttribute(AdcDeviceAttribute&& other) { if (&other != this) { // for (auto& fn : _moveFunc) { for (auto& fn : other._moveFunc) { fn(&other, this); } _copyFunc = std::move(other._copyFunc); _moveFunc = std::move(other._moveFunc); _clearFunc = std::move(other._clearFunc); _ident = std::move(other._ident); _accessType = std::move(other._accessType); _serializerFunc = std::move(other._serializerFunc); _deserializerFunc = std::move(other._deserializerFunc); } } virtual ~AdcDeviceAttribute() { for (auto& fn : _clearFunc) { fn(this); }; } /* PUBLIC METHODS */ IdentT ident() const { return _ident; } AccessType accessType() const { return _accessType; } template AdcDeviceAttribute& addConvertFunc(FromFuncT&& func_from_internal, ToFuncT&& func_to_internal) { // using value_t = ret_value_t; // it must be internal value type // using user_t = ret_value_t; using value_t = traits::attr_internal_t; using user_t = traits::attr_user_t; static_assert(!std::is_null_pointer_v, "Deduced attribute internal type must not be std::nullptr_t!!!"); static_assert(!std::is_null_pointer_v, "Deduced user-defined type must not be std::nullptr_t!!!"); try { if (_accessType != AdcDeviceAttribute::WriteOnly) { auto& getter = _getterFunc.at(this); // throw out_of_range if value_t is invalid _getterFunc[this] = [getter, wrapper = traits::adc_pf_wrapper(std::forward(func_from_internal)), this]() { // auto val = _getterFunc.at(this)(); // throw out_of_range if value_t is invalid auto val = getter(); return std::get<0>(wrapper)(val); // convert from internal type }; } // ignore "from_internal" conversional function for write-only attribute if (_accessType != AdcDeviceAttribute::ReadOnly) { auto& setter = _setterFunc.at(this); // throw out_of_range if value_t is invalid _setterFunc[this] = [setter, wrapper = traits::adc_pf_wrapper(std::forward(func_to_internal)), this](const user_t& val) { value_t value = std::get<0>(wrapper)(val); // convert to internal type // throw out_of_range if value_t is invalid // _setterFunc.at(this)(value); setter(value); }; } // ignore "to_internal" conversional function for read-only attribute } catch (const std::out_of_range&) { throw std::system_error(AdcDeviceAttributeErrorCode::ERROR_INTERNAL_TYPE_MISMATCH); } _clearFunc.emplace_back([](AdcDeviceAttribute* inst) { _getterFunc.erase(inst); _setterFunc.erase(inst); }); // copy instance functions _copyFunc.emplace_back([](const AdcDeviceAttribute* from, AdcDeviceAttribute* to) { _getterFunc.emplace(to, _getterFunc[from]); _setterFunc.emplace(to, _setterFunc[from]); }); // move instance functions _moveFunc.emplace_back([](AdcDeviceAttribute* from, AdcDeviceAttribute* to) { _getterFunc.emplace(to, std::move(_getterFunc[from])); _setterFunc.emplace(to, std::move(_setterFunc[from])); }); return *this; } template operator UT() const { if (_accessType == WriteOnly) { throw std::system_error(AdcDeviceAttributeErrorCode::ERROR_WRITE_ONLY); } using val_t = std::decay_t; try { return _getterFunc.at(this)(); } catch (const std::out_of_range&) { throw std::system_error(AdcDeviceAttributeErrorCode::ERROR_NO_CONV_FUNC); } } template requires(!std::same_as>) AdcDeviceAttribute& operator=(UT&& val) { if (_accessType == ReadOnly) { throw std::system_error(AdcDeviceAttributeErrorCode::ERROR_READ_ONLY); } using val_t = std::decay_t; try { _setterFunc.at(this)(std::forward(val)); } catch (const std::out_of_range&) { throw std::system_error(AdcDeviceAttributeErrorCode::ERROR_NO_CONV_FUNC); } return *this; } AdcDeviceAttribute& operator=(const AdcDeviceAttribute& other) { if (&other != this) { for (auto& fn : other._copyFunc) { fn(&other, this); } _copyFunc = other._copyFunc; _moveFunc = other._moveFunc; _clearFunc = other._clearFunc; _ident = other._ident; _accessType = other._accessType; _serializerFunc = other._serializerFunc; _deserializerFunc = other._deserializerFunc; } return *this; } AdcDeviceAttribute& operator=(AdcDeviceAttribute&& other) { if (&other != this) { for (auto& fn : other._moveFunc) { fn(&other, this); } _copyFunc = std::move(other._copyFunc); _moveFunc = std::move(other._moveFunc); _clearFunc = std::move(other._clearFunc); _ident = std::move(other._ident); _accessType = std::move(other._accessType); _serializerFunc = std::move(other._serializerFunc); _deserializerFunc = std::move(other._deserializerFunc); } return *this; } serialized_t serialize() { if (_accessType == AdcDeviceAttribute::WriteOnly) { throw std::system_error(AdcDeviceAttributeErrorCode::ERROR_WRITE_ONLY); } return _serializerFunc(); } template requires(!std::convertible_to>) ST serialize() { using s_t = std::decay_t; if constexpr (traits::adc_output_char_range && traits::adc_output_char_range) { s_t res; std::ranges::copy(serialize(), std::back_inserter(res)); } else { static_assert(false, "INVALID USER SERIALIZATION TYPE!"); } } AdcDeviceAttribute& deserialize(const serialized_t& sval) { if (_accessType == AdcDeviceAttribute::ReadOnly) { throw std::system_error(AdcDeviceAttributeErrorCode::ERROR_READ_ONLY); } _deserializerFunc(sval); return *this; } template requires(!std::convertible_to, serialized_t>) AdcDeviceAttribute& deserialize(const ST& sval) { using s_t = std::decay_t; if constexpr (traits::adc_input_char_range && traits::adc_input_char_range) { _deserializerFunc(serialized_t(sval.begin(), sval.end())); } else { static_assert(false, "INVALID USER SERIALIZATION TYPE!"); } return *this; } /* some usefull factory functions */ template static AdcDeviceAttribute makeArithAttr(const IdentT& ident, CtorArgTs... ctor_args) { return AdcDeviceAttribute{ident, constants::AdcDefaultTrivialConvTypes, std::forward(ctor_args)...}; } protected: IdentT _ident; AccessType _accessType; template void setupTrivialConvertFuncImpl() { if constexpr (I < std::tuple_size_v) { using elem_t = std::tuple_element_t; if constexpr (!std::is_same_v) { addConvertFunc([](const VT& v) { return static_cast(v); }, [](const elem_t& v) { return static_cast(v); }); } setupTrivialConvertFuncImpl(); } } template void setupTrivialConvertFunc() { setupTrivialConvertFuncImpl(); } }; } // namespace adc