GCC Code Coverage Report
Directory: next/ Exec Total Coverage
File: next/meta.hpp Lines: 1 1 100.0 %
Date: 2023-04-03 07:16:25 Branches: 0 0 - %

Line Branch Exec Source
1
#pragma once
2
3
#include <concepts>
4
#include <tuple>
5
#include <string_view>
6
7
namespace meta {
8
9
#pragma region type_name
10
11
    template <typename T>
12
    constexpr auto type_name() noexcept {
13
        std::string_view name, prefix, suffix;
14
#ifdef __clang__
15
        name = __PRETTY_FUNCTION__;
16
        prefix = "auto type_name() [T = ";
17
        suffix = "]";
18
#elif defined(__GNUC__)
19
        name = __PRETTY_FUNCTION__;
20
        prefix = "constexpr auto type_name() [with T = ";
21
        suffix = "]";
22
#elif defined(_MSC_VER)
23
        name = __FUNCSIG__;
24
        prefix = "auto __cdecl type_name<";
25
        suffix = ">(void) noexcept";
26
#endif
27
        name.remove_prefix(prefix.size());
28
        name.remove_suffix(suffix.size());
29
        return name;
30
    }
31
32
#pragma endregion
33
34
#pragma region Helper functions for CRTP
35
36
    template <typename T> struct crtp {
37
160
      T &underlying() { return static_cast<T &>(*this); }
38
      T const &underlying() const { return static_cast<T const &>(*this); }
39
    };
40
41
#pragma endregion
42
43
#pragma region Concept Function, Function_object, callable
44
45
    // std::invoke<F,Args...> is a way to check if F is a Function or Function-like object. However
46
    // it requires 'Args...', which may not always be available. 'callable<F>' is a concept that identifies
47
    // if 'F' is a regular Function, lambda, or Function object.
48
49
    template<typename F>
50
    concept FunctionObject = requires (F) {
51
        &F::operator();
52
    };
53
54
    template<typename F>
55
    struct is_function_trait : public std::false_type { };
56
57
    template<typename Ret, typename... Args>
58
    struct is_function_trait<Ret(Args...)> : public std::true_type { };
59
60
    template<typename F>
61
    concept Function = is_function_trait<F>::value;
62
63
    template<typename F>
64
    concept Callable = Function<F> || FunctionObject<F>;
65
66
#pragma endregion
67
68
#pragma region Concept predicate
69
70
    // std::predicate<F,Args> requires both Function type and argument types. The latter is redundent.
71
    // predicate<F> operates solely on F and works as expected in case 'F' is a regular Function, lambda
72
    // or Function object
73
74
    template<typename F>
75
    struct is_predicate_trait : public std::false_type { };
76
77
    template<typename... Args>
78
    struct is_predicate_trait<bool(Args...)> : public std::true_type {};
79
80
    template<typename F, typename... Args>
81
    struct is_predicate_trait<bool(F::*)(Args...)> : public std::true_type { };
82
83
    template<typename F, typename... Args>
84
    struct is_predicate_trait<bool(F::*)(Args...) const> : public std::true_type { };
85
86
    template<FunctionObject F>
87
    struct is_predicate_trait<F> : is_predicate_trait<decltype(&F::operator())> { };
88
89
    template<typename F>
90
    concept Predicate = is_predicate_trait<F>::value;
91
92
#pragma endregion
93
94
#pragma region Function signature introspection
95
96
    template<typename Ret, typename... Args>
97
    struct SignatureInterface {
98
        static constexpr std::size_t nargs = sizeof...(Args);
99
100
        using return_arg_t = Ret;
101
        using input_arg_t = std::tuple<Args...>;
102
    };
103
104
    // primary template - should never be instantiated
105
    template<typename F>
106
    struct Signature : SignatureInterface<void,void> {
107
    };
108
109
    template<typename Ret, typename... Args>
110
    struct Signature<Ret(Args...)> : public SignatureInterface<Ret, Args...> {};
111
112
    template<typename Ret, typename F, typename... Args>
113
    struct Signature<Ret(F::*)(Args...)> : public SignatureInterface<Ret, Args...> {};
114
115
    template<typename Ret, typename F, typename... Args>
116
    struct Signature<Ret(F::*)(Args...) const> : public SignatureInterface<Ret, Args...> {};
117
118
    template<FunctionObject F>
119
    struct Signature<F> : public Signature<decltype(&F::operator())> {};
120
121
#pragma endregion
122
123
}
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// #pragma region meta type
144
//
145
// // extract the N'th argument type of a parameter pack
146
// template<size_t N, typename... Ts>
147
// using argument_t = typename std::tuple_element<N, std::tuple<Ts...>>::type;
148
//
149
// // extract the first argument type of a parameter pack
150
// template<typename... Ts >
151
// using first_argument_t = argument_t<0, Ts...>;
152
//
153
// // extract the last argument type of a parameter pack
154
// template<typename... Ts >
155
// using last_argument_t = argument_t<sizeof...(Ts) - 1, Ts...>;
156
//
157
// // extract the N'th argument of a parameter pack
158
// template <int I, class... Ts>
159
// argument_t<I, Ts...> get(Ts&&... ts) {
160
// 	return std::get<I>(std::forward_as_tuple(ts...));
161
// }
162
//
163
// // extract the first argument of a parameter pack
164
// template <class... Ts>
165
// first_argument_t<Ts...> first(Ts&&... ts) {
166
// 	return std::get<0>(std::forward_as_tuple(ts...));
167
// }
168
//
169
// // extract the last argument of a parameter pack
170
// template <class... Ts>
171
// last_argument_t<Ts...> last(Ts&&... ts) {
172
// 	return std::get<(sizeof...(Ts) - 1)>(std::forward_as_tuple(ts...));
173
// }
174
//
175
// #pragma endregion