149 lines
3.8 KiB
C++
149 lines
3.8 KiB
C++
#pragma once
|
|
|
|
#include <format>
|
|
#include <ranges>
|
|
#include <tuple>
|
|
#include <type_traits>
|
|
|
|
|
|
/*
|
|
|
|
ABSTRACT DEVICE COMPONENTS LIBRARY
|
|
|
|
*/
|
|
|
|
|
|
namespace adc::traits
|
|
{
|
|
|
|
// check if type can be used with std::format_to
|
|
// (from
|
|
// https://stackoverflow.com/questions/72430369/how-to-check-that-a-type-is-formattable-using-type-traits-concepts)
|
|
template <typename T>
|
|
concept formattable =
|
|
requires(T v, std::format_context ctx) { std::formatter<std::remove_cvref_t<T>>().format(v, ctx); };
|
|
|
|
|
|
// range of char/const char
|
|
template <typename R, typename CharT = char>
|
|
concept adc_char_range =
|
|
std::ranges::range<R> && std::is_same_v<std::remove_cv_t<std::ranges::range_value_t<R>>, CharT>;
|
|
|
|
|
|
// output range of char/const char
|
|
template <typename R, typename CharT = char>
|
|
concept adc_output_char_range = std::ranges::output_range<R, CharT>;
|
|
|
|
|
|
// range of char/const char
|
|
template <typename R, typename CharT = char>
|
|
concept adc_input_char_range = std::ranges::input_range<R>;
|
|
// concept adc_input_char_range = std::ranges::input_range<CharT>;
|
|
|
|
|
|
// 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, typename = void>
|
|
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(&std::remove_reference_t<F>::operator())> {
|
|
struct adc_func_traits<F, std::enable_if_t<std::is_class_v<F>>> : adc_func_traits<decltype(&F::operator())> {
|
|
};
|
|
|
|
template <typename F>
|
|
struct adc_func_traits<F&> : adc_func_traits<F> {
|
|
};
|
|
|
|
template <typename F>
|
|
struct adc_func_traits<F&&> : adc_func_traits<F> {
|
|
};
|
|
|
|
template <typename T>
|
|
using adc_retval_t = typename adc_func_traits<T>::ret_t;
|
|
|
|
template <typename T>
|
|
using adc_func_arg1_t = typename adc_func_traits<T>::arg1_t;
|
|
|
|
// 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>
|
|
constexpr static 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)...);
|
|
}
|
|
|
|
|
|
// check if type T is one of types in sequence Rest (e.g. adc_is_any<int,char,float,int,std::string>::value == true)
|
|
|
|
template <typename T, typename... Rest>
|
|
struct adc_is_any_of : std::disjunction<std::is_same<T, Rest>...> {
|
|
};
|
|
|
|
template <typename T, typename... Rest>
|
|
static inline constexpr bool adc_is_any_of_v = std::disjunction_v<std::is_same<T, Rest>...>;
|
|
|
|
|
|
|
|
template <typename T>
|
|
struct adc_is_tuple : std::false_type {
|
|
};
|
|
|
|
|
|
template <typename... Ts>
|
|
struct adc_is_tuple<std::tuple<Ts...>> : std::true_type {
|
|
};
|
|
|
|
|
|
template <typename T>
|
|
static inline constexpr bool adc_is_tuple_v = adc_is_tuple<T>::value;
|
|
|
|
} // namespace adc::traits
|