Initial commit
This commit is contained in:
commit
75ec7065d2
74
.gitignore
vendored
Normal file
74
.gitignore
vendored
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
# This file is used to ignore files which are generated
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
*~
|
||||||
|
*.autosave
|
||||||
|
*.a
|
||||||
|
*.core
|
||||||
|
*.moc
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
*.orig
|
||||||
|
*.rej
|
||||||
|
*.so
|
||||||
|
*.so.*
|
||||||
|
*_pch.h.cpp
|
||||||
|
*_resource.rc
|
||||||
|
*.qm
|
||||||
|
.#*
|
||||||
|
*.*#
|
||||||
|
core
|
||||||
|
!core/
|
||||||
|
tags
|
||||||
|
.DS_Store
|
||||||
|
.directory
|
||||||
|
*.debug
|
||||||
|
Makefile*
|
||||||
|
*.prl
|
||||||
|
*.app
|
||||||
|
moc_*.cpp
|
||||||
|
ui_*.h
|
||||||
|
qrc_*.cpp
|
||||||
|
Thumbs.db
|
||||||
|
*.res
|
||||||
|
*.rc
|
||||||
|
/.qmake.cache
|
||||||
|
/.qmake.stash
|
||||||
|
|
||||||
|
# qtcreator generated files
|
||||||
|
*.pro.user*
|
||||||
|
CMakeLists.txt.user*
|
||||||
|
|
||||||
|
# xemacs temporary files
|
||||||
|
*.flc
|
||||||
|
|
||||||
|
# Vim temporary files
|
||||||
|
.*.swp
|
||||||
|
|
||||||
|
# Visual Studio generated files
|
||||||
|
*.ib_pdb_index
|
||||||
|
*.idb
|
||||||
|
*.ilk
|
||||||
|
*.pdb
|
||||||
|
*.sln
|
||||||
|
*.suo
|
||||||
|
*.vcproj
|
||||||
|
*vcproj.*.*.user
|
||||||
|
*.ncb
|
||||||
|
*.sdf
|
||||||
|
*.opensdf
|
||||||
|
*.vcxproj
|
||||||
|
*vcxproj.*
|
||||||
|
|
||||||
|
# MinGW generated files
|
||||||
|
*.Debug
|
||||||
|
*.Release
|
||||||
|
|
||||||
|
# Python byte code
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Binaries
|
||||||
|
# --------
|
||||||
|
*.dll
|
||||||
|
*.exe
|
||||||
|
|
||||||
23
CMakeLists.txt
Normal file
23
CMakeLists.txt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.14)
|
||||||
|
|
||||||
|
project(ADC LANGUAGES CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
set(ADC_DEVICE_HEADERS
|
||||||
|
device/adc_value_holder.h
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
|
add_library(${PROJECT_NAME} INTERFACE ${ADC_DEVICE_HEADERS})
|
||||||
|
target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_20)
|
||||||
|
# target_link_libraries(${PROJECT_NAME} INTERFACE ASIO::ASIO)
|
||||||
|
target_include_directories(
|
||||||
|
${PROJECT_NAME}
|
||||||
|
INTERFACE
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||||
|
$<INSTALL_INTERFACE:include>
|
||||||
|
)
|
||||||
365
device/adc_value_holder.h
Normal file
365
device/adc_value_holder.h
Normal file
@ -0,0 +1,365 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
ABSTRACT DEVICE COMPONENTS LIBRARY
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <any>
|
||||||
|
#include <concepts>
|
||||||
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
|
#include <system_error>
|
||||||
|
#include <tuple>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <typeindex>
|
||||||
|
|
||||||
|
|
||||||
|
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<adc::AdcValueHolderErrorCode> : public true_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace std
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
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<AdcValueHolderErrorCode>(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<int>(ec), AdcValueHolderErrorCategory::get());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
GENERAL-PURPOSE VALUE HOLDER CLASS WITH OPTIONAL VALIDATOR
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
class AdcValueHolder
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
template <typename T>
|
||||||
|
using arg_t = typename traits::adc_func_traits<T>::arg1_t;
|
||||||
|
|
||||||
|
std::function<void(std::any&)> _getterWrapper;
|
||||||
|
std::function<void(const std::any&)> _setterWrapper;
|
||||||
|
|
||||||
|
std::map<std::type_index, std::function<void(std::any&)>> _convertToInternal;
|
||||||
|
std::map<std::type_index, std::function<void(std::any&)>> _convertFromInternal;
|
||||||
|
|
||||||
|
std::type_index _internalTypeIndex;
|
||||||
|
|
||||||
|
constexpr static std::tuple<char, short, int, long, long long, float, double> _defaultConvTypes{};
|
||||||
|
|
||||||
|
public:
|
||||||
|
// always-true validator
|
||||||
|
constexpr static auto AdcValueHolderDummyValidator = [](const auto&) { return true; };
|
||||||
|
|
||||||
|
/* CONSTRUCTORS AND DESTRUCTOR */
|
||||||
|
|
||||||
|
AdcValueHolder(std::invocable<> auto&& getter,
|
||||||
|
std::invocable<const arg_t<decltype(getter)>&> auto&& setter,
|
||||||
|
std::predicate<const arg_t<decltype(getter)>&> auto&& validator = AdcValueHolderDummyValidator)
|
||||||
|
: _internalTypeIndex(std::type_index(typeid(arg_t<decltype(getter)>)))
|
||||||
|
{
|
||||||
|
using value_t = arg_t<decltype(getter)>;
|
||||||
|
|
||||||
|
static_assert(std::is_same_v<value_t, void>, "THE getter MUST NOT RETURN void type!!!");
|
||||||
|
|
||||||
|
using g_t = decltype(getter);
|
||||||
|
_getterWrapper = [wrapper =
|
||||||
|
std::tuple<traits::adc_deduced_type<g_t>>(std::forward<g_t>(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<vld_t, decltype(AdcValueHolderDummyValidator)>) {
|
||||||
|
_setterWrapper = [wrapper = std::tuple<traits::adc_deduced_type<s_t>>(std::forward<s_t>(setter)),
|
||||||
|
this](const std::any& val) {
|
||||||
|
auto& setter = std::get<0>(wrapper);
|
||||||
|
|
||||||
|
setter(std::any_cast<value_t>(val));
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
_setterWrapper = [wrapper = std::tuple<traits::adc_deduced_type<s_t>, traits::adc_deduced_type<vld_t>>(
|
||||||
|
std::forward<s_t>(setter), std::forward<vld_t>(validator)),
|
||||||
|
this](const std::any& val) {
|
||||||
|
auto& setter = std::get<0>(wrapper);
|
||||||
|
auto& validator = std::get<1>(wrapper);
|
||||||
|
|
||||||
|
auto v = std::any_cast<value_t>(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) {};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AdcValueHolder(const AdcValueHolder&) = default;
|
||||||
|
AdcValueHolder(AdcValueHolder&&) = default;
|
||||||
|
|
||||||
|
virtual ~AdcValueHolder() = default;
|
||||||
|
|
||||||
|
|
||||||
|
/* PUBLIC METHODS */
|
||||||
|
|
||||||
|
template <typename UT>
|
||||||
|
AdcValueHolder& addConvertFunc(std::invocable<std::any&> auto&& func_to_internal,
|
||||||
|
std::invocable<std::any&> auto&& func_from_internal)
|
||||||
|
{
|
||||||
|
static_assert(std::is_same_v<UT, void>, "void IS NOT VALID TYPE!!!");
|
||||||
|
|
||||||
|
auto t_index = std::type_index(typeid(UT));
|
||||||
|
|
||||||
|
_convertToInternal[t_index] = std::forward<decltype(func_to_internal)>(func_to_internal);
|
||||||
|
_convertFromInternal[t_index] = std::forward<decltype(func_from_internal)>(func_from_internal);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename UT = void>
|
||||||
|
AdcValueHolder& delConvertFunc()
|
||||||
|
{
|
||||||
|
if constexpr (std::is_same_v<UT, void>) {
|
||||||
|
_convertFromInternal.clear();
|
||||||
|
_convertToInternal.clear();
|
||||||
|
|
||||||
|
_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 <typename UT>
|
||||||
|
operator UT()
|
||||||
|
{
|
||||||
|
std::any val;
|
||||||
|
|
||||||
|
auto t_index = std::type_index(typeid(UT));
|
||||||
|
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<UT>(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename UT>
|
||||||
|
AdcValueHolder& operator=(const UT& value)
|
||||||
|
{
|
||||||
|
std::any val = std::make_any<UT>(value);
|
||||||
|
|
||||||
|
auto t_index = std::type_index(typeid(UT));
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
template <typename ValueT, typename TupleT = decltype(AdcValueHolder::_defaultConvTypes)>
|
||||||
|
friend AdcValueHolder& setupDefaultConvFunc(AdcValueHolder& holder)
|
||||||
|
{
|
||||||
|
auto t_index = std::type_index(typeid(ValueT));
|
||||||
|
|
||||||
|
if (t_index != holder._internalTypeIndex) {
|
||||||
|
throw std::system_error(AdcValueHolderErrorCode::ERROR_INTERNAL_TYPE_MISMATCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
AdcValueHolder::setupDefaultConvertFunc<ValueT, TupleT>(&holder);
|
||||||
|
|
||||||
|
return holder;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/* STATIC HELPER METHODS */
|
||||||
|
|
||||||
|
template <typename VT, size_t I, typename TupleT>
|
||||||
|
static void setupDefaultConvertFuncImpl(AdcValueHolder* holder)
|
||||||
|
{
|
||||||
|
if constexpr (I < std::tuple_size_v<TupleT>) {
|
||||||
|
using elem_t = std::tuple_element_t<I, TupleT>;
|
||||||
|
auto t_index = std::type_index(typeid(elem_t));
|
||||||
|
|
||||||
|
holder->_convertToInternal[t_index] = [](std::any& val) {
|
||||||
|
val = std::make_any<VT>(std::any_cast<elem_t>(val));
|
||||||
|
};
|
||||||
|
|
||||||
|
holder->_convertFromInternal[t_index] = [](std::any& val) {
|
||||||
|
val = std::make_any<elem_t>(std::any_cast<VT>(val));
|
||||||
|
};
|
||||||
|
|
||||||
|
AdcValueHolder::setupDefaultConvertFuncImpl<VT, I + 1, TupleT>(holder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename VT, typename TupleT>
|
||||||
|
static void setupDefaultConvertFunc(AdcValueHolder* holder)
|
||||||
|
{
|
||||||
|
setupDefaultConvertFuncImpl<VT, 0, TupleT>(holder);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace adc
|
||||||
Loading…
x
Reference in New Issue
Block a user