#pragma once #include #include #include namespace mcc::traits { template static constexpr size_t mcc_range_size(const R& r) { if constexpr (std::ranges::sized_range) { return r.size(); } else { return std::ranges::distance(r.begin(), r.end()); } } template concept mcc_char_view = std::ranges::view && std::same_as, char>; // input range of char/const char template concept mcc_input_char_range = std::ranges::input_range && std::is_same_v>, CharT>; // output range of char/const char template concept mcc_output_char_range = std::ranges::output_range && std::same_as>, CharT>; template concept mcc_view_or_output_char_range = mcc_char_view || mcc_output_char_range; template concept mcc_range_of_input_char_range = std::ranges::range && traits::mcc_input_char_range>; template concept mcc_range_of_output_char_range = std::ranges::range && traits::mcc_output_char_range>; // https://stackoverflow.com/questions/72430369/how-to-check-that-a-type-is-formattable-using-type-traits-concepts) template concept mcc_formattable = requires(T v, std::format_context ctx) { std::formatter>().format(v, ctx); }; // from https://stackoverflow.com/questions/74383254/concept-that-models-only-the-stdchrono-duration-types template concept mcc_time_duration_c = requires { [](std::type_identity>) { }(std::type_identity>()); }; template concept mcc_systime_c = requires { [](std::type_identity>) {}(std::type_identity>()); }; template concept mcc_output_duration_range_c = std::ranges::output_range> && mcc_time_duration_c>; // concept mcc_output_duration_range_c = std::ranges::range && requires(R r) { // [](std::type_identity>) { // }(std::ranges::range_value_t()); // }; /* a callable concept and its signature traits */ template concept mcc_is_callable = std::is_function_v || (std::is_object_v && requires(T) { &T::operator(); }); template concept mcc_callable_c = std::is_function_v || (std::is_object_v && requires(T) { &T::operator(); }); // helper classes for callable signature deducing template struct mcc_func_traits_helper_t; template struct mcc_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 mcc_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; }; template struct mcc_func_traits { // use of an empty struct here to match std::invoke_result behaivior (at least of GCC) }; template struct mcc_func_traits : mcc_func_traits_helper_t { }; template struct mcc_func_traits : mcc_func_traits_helper_t { }; template struct mcc_func_traits : mcc_func_traits_helper_t { }; template struct mcc_func_traits : mcc_func_traits_helper_t { }; template requires mcc_is_callable struct mcc_func_traits : mcc_func_traits { }; // reference/const ref and rvalue helpers template struct mcc_func_traits : mcc_func_traits { }; template struct mcc_func_traits : mcc_func_traits { }; template struct mcc_func_traits : mcc_func_traits { }; // type of the returned value template using mcc_retval_t = typename mcc_func_traits::ret_t; // type of the first argument of callable template using mcc_func_arg1_t = typename mcc_func_traits::arg1_t; // type of the N-th argument of callable // NOTE: starts from 1 not from 0!!! template using mcc_func_argN_t = std::conditional_t= mcc_func_traits::arity, std::tuple_element_t::args_t>, void>; // non-const lvalue reference, constructible from CtorArgTs (an output argument of function) template concept mcc_output_arg_c = !std::is_const_v> && std::is_lvalue_reference_v && std::constructible_from, CtorArgTs...>; // std::tuple or std::pair template concept mcc_tuple_c = requires { requires requires { [](std::type_identity>) {}(std::type_identity>()); } || requires { [](std::type_identity>) { }(std::type_identity>()); }; }; template concept mcc_nonconst_lvref = std::is_lvalue_reference_v && !std::is_const_v>; template concept mcc_error_c = std::convertible_to || requires(const T t) { { t.operator bool() }; }; namespace details { // compile-time hash for type // (from https://stackoverflow.com/questions/56292104/hashing-types-at-compile-time-in-c17-c2a) // WARNING: it does not work for unnamed struct!!! template static consteval size_t Hash() { size_t result{}; #ifdef _MSC_VER for (const auto& c : __FUNCSIG__) #else // GCC and clang for (const auto& c : __PRETTY_FUNCTION__) #endif (result ^= c) <<= 1; return result; } } // namespace details template static constexpr size_t mcc_type_hash = details::Hash(); static constexpr size_t mcc_hash_combine(size_t lhs, size_t rhs) { constexpr size_t v_const = sizeof(size_t) >= 8 ? 0x517cc1b727220a95 : 0x9e3779b9; lhs ^= rhs + v_const + (lhs << 6) + (lhs >> 2); return lhs; } template static constexpr size_t mcc_type_pair_hash() { return mcc_hash_combine(mcc_type_hash, mcc_type_hash); } } // namespace mcc::traits