This commit is contained in:
Timur A. Fatkhullin 2024-01-20 17:01:09 +03:00
parent 75ec7065d2
commit d9c87aed1f
5 changed files with 229 additions and 76 deletions

View File

@ -5,14 +5,21 @@ project(ADC LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(ADC_COMMON_HEADERS
common/adc_value_holder.h
)
set(ADC_DEVICE_HEADERS set(ADC_DEVICE_HEADERS
device/adc_value_holder.h device/adc_device_attribute.h
device/adc_device_command.h
) )
include(GNUInstallDirs) 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_compile_features(${PROJECT_NAME} INTERFACE cxx_std_20)
# target_link_libraries(${PROJECT_NAME} INTERFACE ASIO::ASIO) # target_link_libraries(${PROJECT_NAME} INTERFACE ASIO::ASIO)
target_include_directories( target_include_directories(

83
common/adc_traits.h Normal file
View File

@ -0,0 +1,83 @@
#pragma once
#include <tuple>
#include <type_traits>
/*
ABSTRACT DEVICE COMPONENTS LIBRARY
*/
namespace adc::traits
{
// deduce returned type of callable
template <typename T>
using adc_retval_t = std::invoke_result_t<std::remove_cvref_t<T>>;
// helper classes
template <typename... Ts>
struct adc_func_traits_helper_t;
template <typename R>
struct adc_func_traits_helper_t<R> {
using ret_t = R;
using args_t = std::tuple<>;
using arg1_t = void;
};
template <typename R, typename Arg, typename... Args>
struct adc_func_traits_helper_t<R, Arg, Args...> {
using ret_t = R;
using args_t = std::tuple<Arg, Args...>;
using arg1_t = Arg;
};
// callable traits
template <typename F>
struct adc_func_traits;
template <typename R, typename... Args>
struct adc_func_traits<R (*)(Args...)> : adc_func_traits_helper_t<R, Args...> {
};
template <typename R, typename... Args>
struct adc_func_traits<R(Args...)> : adc_func_traits_helper_t<R, Args...> {
};
template <typename C, typename R, typename... Args>
struct adc_func_traits<R (C::*)(Args...)> : adc_func_traits_helper_t<R, Args...> {
};
template <typename C, typename R, typename... Args>
struct adc_func_traits<R (C::*)(Args...) const> : adc_func_traits_helper_t<R, Args...> {
};
template <typename F>
struct adc_func_traits : adc_func_traits<decltype(&F::operator())> {
};
// deduce type
template <typename T>
using adc_deduced_type =
std::conditional_t<std::is_lvalue_reference_v<T> && !std::is_const_v<std::remove_reference_t<T>>,
T,
std::remove_cvref_t<T>>;
// perfect-forwarding wrapper
template <typename T, typename... Ts>
auto adc_pf_wrapper(T&& v, Ts&&... vs)
{
return std::tuple<adc_deduced_type<T>, adc_deduced_type<Ts>...>(std::forward<T>(v), std::forward<Ts>(vs)...);
}
} // namespace adc::traits

View File

@ -11,11 +11,11 @@
#include <concepts> #include <concepts>
#include <functional> #include <functional>
#include <map> #include <map>
#include <ranges>
#include <system_error> #include <system_error>
#include <tuple>
#include <type_traits>
#include <typeindex> #include <typeindex>
#include "adc_traits.h"
namespace adc namespace adc
{ {
@ -46,70 +46,6 @@ namespace adc
{ {
namespace traits
{
// deduce returned type of callable
template <typename T>
using adc_retval_t = std::invoke_result_t<std::remove_cvref_t<T>>;
// helper classes
template <typename... Ts>
struct adc_func_traits_helper_t;
template <typename R>
struct adc_func_traits_helper_t<R> {
using ret_t = R;
using args_t = std::tuple<>;
using arg1_t = void;
};
template <typename R, typename Arg, typename... Args>
struct adc_func_traits_helper_t<R, Arg, Args...> {
using ret_t = R;
using args_t = std::tuple<Arg, Args...>;
using arg1_t = Arg;
};
// callable traits
template <typename F>
struct adc_func_traits;
template <typename R, typename... Args>
struct adc_func_traits<R (*)(Args...)> : adc_func_traits_helper_t<R, Args...> {
};
template <typename R, typename... Args>
struct adc_func_traits<R(Args...)> : adc_func_traits_helper_t<R, Args...> {
};
template <typename C, typename R, typename... Args>
struct adc_func_traits<R (C::*)(Args...)> : adc_func_traits_helper_t<R, Args...> {
};
template <typename C, typename R, typename... Args>
struct adc_func_traits<R (C::*)(Args...) const> : adc_func_traits_helper_t<R, Args...> {
};
template <typename F>
struct adc_func_traits : adc_func_traits<decltype(&F::operator())> {
};
// deduce type
template <typename T>
using adc_deduced_type =
std::conditional_t<std::is_lvalue_reference_v<T> && !std::is_const_v<std::remove_reference_t<T>>,
T,
std::remove_cvref_t<T>>;
} // namespace traits
// error category // error category
struct AdcValueHolderErrorCategory : public std::error_category { struct AdcValueHolderErrorCategory : public std::error_category {
@ -161,7 +97,7 @@ class AdcValueHolder
{ {
protected: protected:
template <typename T> template <typename T>
using arg_t = typename traits::adc_func_traits<T>::arg1_t; using arg_t = typename traits::adc_func_traits<T>::ret_t;
std::function<void(std::any&)> _getterWrapper; std::function<void(std::any&)> _getterWrapper;
std::function<void(const std::any&)> _setterWrapper; std::function<void(const std::any&)> _setterWrapper;
@ -189,8 +125,7 @@ public:
static_assert(std::is_same_v<value_t, void>, "THE getter MUST NOT RETURN void type!!!"); static_assert(std::is_same_v<value_t, void>, "THE getter MUST NOT RETURN void type!!!");
using g_t = decltype(getter); using g_t = decltype(getter);
_getterWrapper = [wrapper = _getterWrapper = [wrapper = traits::adc_pf_wrapper(std::forward<g_t>(getter))](std::any& val) {
std::tuple<traits::adc_deduced_type<g_t>>(std::forward<g_t>(getter))](std::any& val) {
auto& getter = std::get<0>(wrapper); auto& getter = std::get<0>(wrapper);
val = getter(); val = getter();
}; };
@ -199,16 +134,15 @@ public:
using vld_t = decltype(validator); using vld_t = decltype(validator);
using s_t = decltype(setter); using s_t = decltype(setter);
if constexpr (std::is_same_v<vld_t, decltype(AdcValueHolderDummyValidator)>) { if constexpr (std::is_same_v<vld_t, decltype(AdcValueHolderDummyValidator)>) { // no validation
_setterWrapper = [wrapper = std::tuple<traits::adc_deduced_type<s_t>>(std::forward<s_t>(setter)), _setterWrapper = [wrapper = traits::adc_pf_wrapper(std::forward<s_t>(setter)), this](const std::any& val) {
this](const std::any& val) {
auto& setter = std::get<0>(wrapper); auto& setter = std::get<0>(wrapper);
setter(std::any_cast<value_t>(val)); setter(std::any_cast<value_t>(val));
}; };
} else { } else {
_setterWrapper = [wrapper = std::tuple<traits::adc_deduced_type<s_t>, traits::adc_deduced_type<vld_t>>( _setterWrapper = [wrapper =
std::forward<s_t>(setter), std::forward<vld_t>(validator)), traits::adc_pf_wrapper(std::forward<s_t>(setter), std::forward<vld_t>(validator)),
this](const std::any& val) { this](const std::any& val) {
auto& setter = std::get<0>(wrapper); auto& setter = std::get<0>(wrapper);
auto& validator = std::get<1>(wrapper); auto& validator = std::get<1>(wrapper);
@ -239,6 +173,17 @@ public:
/* PUBLIC METHODS */ /* PUBLIC METHODS */
std::type_index valueTypeIndex() const { return _internalTypeIndex; }
std::vector<std::type_index> convTypeIndices()
{
auto kv = std::views::keys(_convertFromInternal);
return {kv.begin(), kv.end()};
}
template <typename UT> template <typename UT>
AdcValueHolder& addConvertFunc(std::invocable<std::any&> auto&& func_to_internal, AdcValueHolder& addConvertFunc(std::invocable<std::any&> auto&& func_to_internal,
std::invocable<std::any&> auto&& func_from_internal) std::invocable<std::any&> auto&& func_from_internal)

View File

@ -0,0 +1 @@
#pragma once

117
device/adc_device_command.h Normal file
View File

@ -0,0 +1,117 @@
#pragma once
/*
ABSTRACT DEVICE COMPONENTS LIBRARY
*/
#include <memory>
#include <string>
#include "../common/adc_value_holder.h"
/*
*/
namespace adc
{
template <typename IdentT, typename SerializedT = std::string>
class AdcDeviceCommand
{
protected:
IdentT _ident;
std::unique_ptr<AdcValueHolder> _commandArgUptr;
std::function<void()> _execFuncWrapper;
std::function<void(std::any&)> _deserializerWrapper;
public:
typedef IdentT ident_t;
typedef SerializedT serialized_t;
template <typename ExecFuncT,
typename DeserializerT,
typename ValidatorT = decltype(AdcValueHolder::AdcValueHolderDummyValidator)>
AdcDeviceCommand(const IdentT& ident,
ExecFuncT&& exec_func,
DeserializerT&& deserializer,
ValidatorT&& validator = AdcValueHolder::AdcValueHolderDummyValidator)
: _ident(ident), _commandArgUptr()
{
using sign_t = traits::adc_func_traits<ExecFuncT>;
static_assert(std::tuple_size_v<typename sign_t::args_t> > 1,
"COMMAND EXECUTION FUNCTION MUST ACCEPT 0 OR EXACTLY 1 ARGUMENT!!!");
if constexpr (std::tuple_size_v<typename sign_t::args_t>) { // command with argument
using value_t = typename sign_t::arg1_t;
static_assert(std::predicate<ValidatorT, const value_t&>, "INVALID TYPE OF VALIDATOR");
static_assert(std::invocable<DeserializerT, const SerializedT&>, "INVALID TYPE OF DESERIALIZER");
static_assert(std::is_convertible_v<std::invoke_result_t<DeserializerT, const SerializedT&>, value_t>,
"INVALID RETURN TYPE OF DESERIALIZER");
auto command_arg = std::shared_ptr<value_t>(value_t());
_commandArgUptr = std::make_unique<AdcValueHolder>(
[command_arg]() { return *command_arg; }, [command_arg](const value_t& value) { *command_arg = value; },
std::forward<ValidatorT>(validator));
_execFuncWrapper = [wrapper = traits::adc_pf_wrapper(std::forward<ExecFuncT>(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<DeserializerT>(deserializer))](std::any& val) {
auto& deserializer = std::get<0>(wrapper);
val = std::make_any<value_t>(deserializer(std::any_cast<SerializedT>(val)));
};
// setup only convert-to-native-value function (deserializer)
_commandArgUptr->addConvertFunc<SerializedT>(std::forward<DeserializerT>(deserializer), []() {});
} else { // command without argument (ignore deserializer and validator)
_execFuncWrapper = std::forward<ExecFuncT>(exec_func);
}
}
virtual ~AdcDeviceCommand() = default;
/* PUBLIC METHODS */
IdentT ident() const { return ident; }
template <typename ValueT>
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