#pragma once #include #include #include #include #include /* 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 concept formattable = requires(T v, std::format_context ctx) { std::formatter>().format(v, ctx); }; // range of char/const char template concept adc_char_range = std::ranges::range && std::is_same_v>, CharT>; // output range of char/const char template concept adc_output_char_range = std::ranges::output_range && std::same_as>, CharT>; // range of char/const char template concept adc_input_char_range = std::ranges::input_range && std::is_same_v>, CharT>; template concept adc_char_view = std::ranges::view && std::same_as, char>; template concept adc_view_or_output_char_range = adc_char_view || adc_output_char_range; template concept adc_range_of_view_char_range = std::ranges::range && std::ranges::view> && std::same_as>, char>; template concept adc_range_of_input_char_range = std::ranges::range && traits::adc_input_char_range>; template concept adc_range_of_output_char_range = std::ranges::range && traits::adc_output_char_range>; template concept adc_range_of_view_or_output_char_range = adc_range_of_view_char_range || adc_output_char_range; // 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; static constexpr size_t arity = 0; }; template struct adc_func_traits_helper_t { using ret_t = R; using args_t = std::tuple; using arg1_t = Arg; static constexpr size_t arity = sizeof...(Args) + 1; }; // callable concept and its signature traits template concept adc_is_callable = std::is_function_v || (std::is_object_v && requires(T) { &T::operator(); }); // std::is_function_v || (std::is_object_v && requires(T) { std::is_function_v; }); template struct adc_func_traits { // use of an empty struct here to match std::invoke_result behaivior (at least of GCC) }; // special case template <> struct adc_func_traits { using ret_t = std::nullptr_t; using args_t = std::tuple<>; using arg1_t = std::nullptr_t; static constexpr size_t arity = 0; }; 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 requires adc_is_callable struct adc_func_traits : adc_func_traits { }; template struct adc_func_traits : adc_func_traits { }; template struct adc_func_traits : adc_func_traits { }; template struct adc_func_traits : adc_func_traits { }; template using adc_retval_t = typename adc_func_traits::ret_t; template using adc_func_arg1_t = typename adc_func_traits::arg1_t; // deduce type template using adc_deduced_type = std::conditional_t && !std::is_const_v>, T&, std::remove_cvref_t>; // perfect-forwarding wrapper template constexpr static auto adc_pf_wrapper(T&& v, Ts&&... vs) { return std::tuple, adc_deduced_type...>(std::forward(v), std::forward(vs)...); } // check if type T is one of types in sequence Rest (e.g. adc_is_any::value == true) template struct adc_is_any_of : std::disjunction...> { }; template static inline constexpr bool adc_is_any_of_v = std::disjunction_v...>; template struct adc_is_tuple : std::false_type { }; template struct adc_is_tuple : adc_is_tuple { }; template struct adc_is_tuple : adc_is_tuple { }; template struct adc_is_tuple : adc_is_tuple { }; template struct adc_is_tuple> : std::true_type { }; template struct adc_is_tuple> : std::true_type { }; template static inline constexpr bool adc_is_tuple_v = adc_is_tuple::value; template concept adc_tuple_like = adc_is_tuple_v == true; template // from https://stackoverflow.com/questions/74383254/concept-that-models-only-the-stdchrono-duration-types concept adc_time_duration_c = requires { [](std::type_identity>) { }(std::type_identity>()); }; template struct adc_duration_common_type; template struct adc_duration_common_type : std::common_type { }; template struct adc_duration_common_type : adc_duration_common_type, Ts...> { }; template using adc_duration_common_type_t = typename adc_duration_common_type::type; /* all STL helper duration types */ using adc_common_duration_t = adc_duration_common_type_t; } // namespace adc::traits