From d9c87aed1fdc930152c3f05b9af1e242ec574892 Mon Sep 17 00:00:00 2001 From: "Timur A. Fatkhullin" Date: Sat, 20 Jan 2024 17:01:09 +0300 Subject: [PATCH] ... --- CMakeLists.txt | 11 ++- common/adc_traits.h | 83 ++++++++++++++++++ {device => common}/adc_value_holder.h | 93 +++++--------------- device/adc_device_attribute.h | 1 + device/adc_device_command.h | 117 ++++++++++++++++++++++++++ 5 files changed, 229 insertions(+), 76 deletions(-) create mode 100644 common/adc_traits.h rename {device => common}/adc_value_holder.h (78%) create mode 100644 device/adc_device_attribute.h create mode 100644 device/adc_device_command.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d427221..d6afee4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,14 +5,21 @@ project(ADC LANGUAGES CXX) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) + +set(ADC_COMMON_HEADERS + common/adc_value_holder.h +) + set(ADC_DEVICE_HEADERS - device/adc_value_holder.h + device/adc_device_attribute.h + device/adc_device_command.h ) include(GNUInstallDirs) -add_library(${PROJECT_NAME} INTERFACE ${ADC_DEVICE_HEADERS}) +add_library(${PROJECT_NAME} INTERFACE ${ADC_COMMON_HEADERS} ${ADC_DEVICE_HEADERS} + common/adc_traits.h) target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_20) # target_link_libraries(${PROJECT_NAME} INTERFACE ASIO::ASIO) target_include_directories( diff --git a/common/adc_traits.h b/common/adc_traits.h new file mode 100644 index 0000000..2ba4110 --- /dev/null +++ b/common/adc_traits.h @@ -0,0 +1,83 @@ +#pragma once + +#include +#include + + +/* + + ABSTRACT DEVICE COMPONENTS LIBRARY + +*/ + + +namespace adc::traits +{ + +// deduce returned type of callable +template +using adc_retval_t = std::invoke_result_t>; + + +// helper classes +template +struct adc_func_traits_helper_t; + +template +struct adc_func_traits_helper_t { + using ret_t = R; + using args_t = std::tuple<>; + using arg1_t = void; +}; + +template +struct adc_func_traits_helper_t { + using ret_t = R; + using args_t = std::tuple; + using arg1_t = Arg; +}; + + +// callable traits + +template +struct adc_func_traits; + +template +struct adc_func_traits : adc_func_traits_helper_t { +}; + +template +struct adc_func_traits : adc_func_traits_helper_t { +}; + +template +struct adc_func_traits : adc_func_traits_helper_t { +}; + +template +struct adc_func_traits : adc_func_traits_helper_t { +}; + +template +struct adc_func_traits : adc_func_traits { +}; + + +// deduce type +template +using adc_deduced_type = + std::conditional_t && !std::is_const_v>, + T, + std::remove_cvref_t>; + + +// perfect-forwarding wrapper +template +auto adc_pf_wrapper(T&& v, Ts&&... vs) +{ + return std::tuple, adc_deduced_type...>(std::forward(v), std::forward(vs)...); +} + + +} // namespace adc::traits diff --git a/device/adc_value_holder.h b/common/adc_value_holder.h similarity index 78% rename from device/adc_value_holder.h rename to common/adc_value_holder.h index 8a9774d..fa0bb09 100644 --- a/device/adc_value_holder.h +++ b/common/adc_value_holder.h @@ -11,11 +11,11 @@ #include #include #include +#include #include -#include -#include #include +#include "adc_traits.h" namespace adc { @@ -46,70 +46,6 @@ namespace adc { -namespace traits -{ - -// deduce returned type of callable -template -using adc_retval_t = std::invoke_result_t>; - - -// helper classes -template -struct adc_func_traits_helper_t; - -template -struct adc_func_traits_helper_t { - using ret_t = R; - using args_t = std::tuple<>; - using arg1_t = void; -}; - -template -struct adc_func_traits_helper_t { - using ret_t = R; - using args_t = std::tuple; - using arg1_t = Arg; -}; - - -// callable traits - -template -struct adc_func_traits; - -template -struct adc_func_traits : adc_func_traits_helper_t { -}; - -template -struct adc_func_traits : adc_func_traits_helper_t { -}; - -template -struct adc_func_traits : adc_func_traits_helper_t { -}; - -template -struct adc_func_traits : adc_func_traits_helper_t { -}; - -template -struct adc_func_traits : adc_func_traits { -}; - - -// deduce type -template -using adc_deduced_type = - std::conditional_t && !std::is_const_v>, - T, - std::remove_cvref_t>; - - -} // namespace traits - - // error category struct AdcValueHolderErrorCategory : public std::error_category { @@ -161,7 +97,7 @@ class AdcValueHolder { protected: template - using arg_t = typename traits::adc_func_traits::arg1_t; + using arg_t = typename traits::adc_func_traits::ret_t; std::function _getterWrapper; std::function _setterWrapper; @@ -189,8 +125,7 @@ public: static_assert(std::is_same_v, "THE getter MUST NOT RETURN void type!!!"); using g_t = decltype(getter); - _getterWrapper = [wrapper = - std::tuple>(std::forward(getter))](std::any& val) { + _getterWrapper = [wrapper = traits::adc_pf_wrapper(std::forward(getter))](std::any& val) { auto& getter = std::get<0>(wrapper); val = getter(); }; @@ -199,16 +134,15 @@ public: using vld_t = decltype(validator); using s_t = decltype(setter); - if constexpr (std::is_same_v) { - _setterWrapper = [wrapper = std::tuple>(std::forward(setter)), - this](const std::any& val) { + 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 = std::tuple, traits::adc_deduced_type>( - std::forward(setter), std::forward(validator)), + _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); @@ -239,6 +173,17 @@ public: /* PUBLIC METHODS */ + + std::type_index valueTypeIndex() const { return _internalTypeIndex; } + + + std::vector convTypeIndices() + { + auto kv = std::views::keys(_convertFromInternal); + return {kv.begin(), kv.end()}; + } + + template AdcValueHolder& addConvertFunc(std::invocable auto&& func_to_internal, std::invocable auto&& func_from_internal) diff --git a/device/adc_device_attribute.h b/device/adc_device_attribute.h new file mode 100644 index 0000000..6f70f09 --- /dev/null +++ b/device/adc_device_attribute.h @@ -0,0 +1 @@ +#pragma once diff --git a/device/adc_device_command.h b/device/adc_device_command.h new file mode 100644 index 0000000..b823ec9 --- /dev/null +++ b/device/adc_device_command.h @@ -0,0 +1,117 @@ +#pragma once + + +/* + + ABSTRACT DEVICE COMPONENTS LIBRARY + +*/ + +#include +#include +#include "../common/adc_value_holder.h" + +/* + +*/ + +namespace adc +{ + +template +class AdcDeviceCommand +{ +protected: + IdentT _ident; + + std::unique_ptr _commandArgUptr; + + std::function _execFuncWrapper; + std::function _deserializerWrapper; + +public: + typedef IdentT ident_t; + typedef SerializedT serialized_t; + + + template + AdcDeviceCommand(const IdentT& ident, + ExecFuncT&& exec_func, + DeserializerT&& deserializer, + ValidatorT&& validator = AdcValueHolder::AdcValueHolderDummyValidator) + : _ident(ident), _commandArgUptr() + { + using sign_t = traits::adc_func_traits; + + static_assert(std::tuple_size_v > 1, + "COMMAND EXECUTION FUNCTION MUST ACCEPT 0 OR EXACTLY 1 ARGUMENT!!!"); + + if constexpr (std::tuple_size_v) { // command with argument + using value_t = typename sign_t::arg1_t; + + static_assert(std::predicate, "INVALID TYPE OF VALIDATOR"); + + static_assert(std::invocable, "INVALID TYPE OF DESERIALIZER"); + static_assert(std::is_convertible_v, value_t>, + "INVALID RETURN TYPE OF DESERIALIZER"); + + + auto command_arg = std::shared_ptr(value_t()); + + _commandArgUptr = std::make_unique( + [command_arg]() { return *command_arg; }, [command_arg](const value_t& value) { *command_arg = value; }, + std::forward(validator)); + + _execFuncWrapper = [wrapper = traits::adc_pf_wrapper(std::forward(exec_func)), this]() { + auto& exec_func = std::get<0>(wrapper); + value_t val = *_commandArgUptr; + exec_func(val); + }; + + + _deserializerWrapper = + [wrapper = traits::adc_pf_wrapper(std::forward(deserializer))](std::any& val) { + auto& deserializer = std::get<0>(wrapper); + val = std::make_any(deserializer(std::any_cast(val))); + }; + + // setup only convert-to-native-value function (deserializer) + _commandArgUptr->addConvertFunc(std::forward(deserializer), []() {}); + } else { // command without argument (ignore deserializer and validator) + _execFuncWrapper = std::forward(exec_func); + } + } + + + virtual ~AdcDeviceCommand() = default; + + + /* PUBLIC METHODS */ + + IdentT ident() const { return ident; } + + + template + void operator()(const ValueT& value) + { + if (_commandArgUptr) { // command with argument + *_commandArgUptr = value; + } + _execFuncWrapper(); + } + + + void operator()() + { + if (_commandArgUptr) { // command with argument + throw 1; + } + + _execFuncWrapper(); + } +}; + + +} // namespace adc