From 53779d2f13220f9ca3517da41dafda13fdce0dda Mon Sep 17 00:00:00 2001 From: "Timur A. Fatkhullin" Date: Thu, 11 Apr 2024 22:11:24 +0300 Subject: [PATCH] add new AdcValueHolder implementation in adc_value.h --- CMakeLists.txt | 4 +- common/adc_value.h | 430 +++++++++++++++++++++++++++++++++ tests/adc_valueholder_test.cpp | 19 +- 3 files changed, 444 insertions(+), 9 deletions(-) create mode 100644 common/adc_value.h diff --git a/CMakeLists.txt b/CMakeLists.txt index f9527ec..8625575 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,8 +8,8 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(ADC_COMMON_HEADERS common/adc_traits.h - common/adc_value_holder.h -) + common/adc_value_holder.h + common/adc_value.h) set(ADC_DEVICE_HEADERS device/adc_device_attribute.h diff --git a/common/adc_value.h b/common/adc_value.h new file mode 100644 index 0000000..b293e57 --- /dev/null +++ b/common/adc_value.h @@ -0,0 +1,430 @@ +#pragma once + +/* + + ABSTRACT DEVICE COMPONENTS LIBRARY + + */ + + +#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 + inline static std::unordered_map> _getterFunc{}; + + template + inline static std::unordered_map> _setterFunc{}; + + 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); + using s_t = decltype(setter); + using vld_t = decltype(validator); + + _getterFunc[this] = [wrapper = traits::adc_pf_wrapper(std::forward(getter))]() { + return std::get<0>(wrapper)(); + }; + + + _setterFunc[this] = [wrapper = + traits::adc_pf_wrapper(std::forward(setter), + std::forward(validator))](const value_t& val) { + if (std::get<1>(wrapper)(val)) { + std::get<0>(wrapper)(val); + } else { + throw std::system_error(AdcValueHolderErrorCode::ERROR_VALUE_IS_NOT_VALID); + } + }; + } + +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 + { + 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>(); + } + + + 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 */ + + + template , + typename VT = decltype(AdcValueHolder::AdcValueHolderDummyValidator)> + AdcValueHolder& resetValueHolder(GT&& getter, + std::invocable auto&& setter, + VT&& validator = AdcValueHolder::AdcValueHolderDummyValidator) + requires std::invocable && std::predicate + { + 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>(); + + 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(FromFuncT&& func_from_internal, ToFuncT&& func_to_internal) + // requires std::invocable>> && + // std::invocable>> + { + using from_sig_t = typename traits::adc_func_traits; + using to_sig_t = typename traits::adc_func_traits; + using value_t = typename to_sig_t::ret_t; // internal value type + using user_t = typename from_sig_t::ret_t; + + // static_assert(!std::is_same_v, "void IS NOT VALID TYPE!!!"); + + // static_assert(!std::is_void_v::arg1_t>, + // "INVALID CONVERSIONAL FUNCTION!!!"); + + // static_assert(std::is_same_v::arg1_t>, + // value_t>, + // "INVALID CONVERSIONAL FUNCTION!!!"); + + _getterFunc[this] = [wrapper = traits::adc_pf_wrapper(std::forward(func_from_internal)), + this]() { + if (_getterFunc[this]) { + auto val = _getterFunc[this](); + return std::get<0>(wrapper)(val); // convert from internal type + } + // invalid conversion function signature + throw std::system_error(AdcValueHolderErrorCode::ERROR_INTERNAL_TYPE_MISMATCH); + }; + + + _setterFunc[this] = [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 + if (_setterFunc[this]) { + _setterFunc[this](value); + } else { + // invalid conversion function signature + throw std::system_error(AdcValueHolderErrorCode::ERROR_INTERNAL_TYPE_MISMATCH); + } + }; + + return *this; + } + + + template + operator UT() + { + using v_t = std::remove_reference_t; + using val_t = std::conditional_t, std::add_pointer_t>, v_t>; + + auto getter = _getterFunc[this]; + if (getter) { + return getter(); + } + + throw std::system_error(AdcValueHolderErrorCode::ERROR_NO_CONV_FUNC); + } + + template + AdcValueHolder& operator=(UT&& value) + { + // using v_t = std::remove_reference_t; + using v_t = std::remove_cvref_t; + using val_t = std::conditional_t, std::add_pointer_t>, v_t>; + + auto setter = _setterFunc[this]; + if (setter) { + setter(std::forward(value)); + } else { + throw std::system_error(AdcValueHolderErrorCode::ERROR_NO_CONV_FUNC); + } + + return *this; + } + + + AdcValueHolder& operator=(AdcValueHolder&& other) = default; + AdcValueHolder& operator=(const AdcValueHolder& other) = default; + + +protected: + /* STATIC HELPER METHODS */ + + 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); }); + } + + AdcValueHolder::setupTrivialConvertFuncImpl(); + } + } + + template + void setupTrivialConvertFunc() + { + setupTrivialConvertFuncImpl(); + } +}; + + +/* + 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 diff --git a/tests/adc_valueholder_test.cpp b/tests/adc_valueholder_test.cpp index 07b7f0e..af0bc7b 100644 --- a/tests/adc_valueholder_test.cpp +++ b/tests/adc_valueholder_test.cpp @@ -4,7 +4,8 @@ #include #include "../common/adc_utils.h" -#include "../common/adc_value_holder.h" +// #include "../common/adc_value_holder.h" +#include "../common/adc_value.h" TEST_CASE("[ADC VALUEHOLDER]") { @@ -36,7 +37,9 @@ TEST_CASE("[ADC VALUEHOLDER]") CHECK_THROWS_WITH_AS(vh = 1.1, "conversion function is not defined", std::system_error); CHECK_THROWS_WITH_AS(vh = -3, "user value is not valid", std::system_error); - double dv = 33.33; + std::cout << "int_val = " << int_val << "\n"; + + const double dv = 33.33; vah = dv; REQUIRE_EQ(int_val, 33); @@ -66,13 +69,15 @@ TEST_CASE("[ADC VALUEHOLDER]") adc::AdcValueHolder vsh(sget, sset, sval); - vsh.addConvertFunc([](std::any& v) { v = std::string(std::any_cast(v)); }, - [](std::any& v) { - auto sval = std::any_cast(&v); - v = sval->c_str(); - }); + // vsh.addConvertFunc([](std::any& v) { v = std::string(std::any_cast(v)); }, + // [](std::any& v) { + // auto sval = std::any_cast(&v); + // v = sval->c_str(); + // }); + vsh.addConvertFunc([](const std::string& v) { return v.c_str(); }, [](const char* v) { return std::string(v); }); + vsh = "NEW VALUE"; REQUIRE_EQ(str, "NEW VALUE");