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