inkcpp
Loading...
Searching...
No Matches
traits.h
1/* Copyright (c) 2024 Julian Benda
2 *
3 * This file is part of inkCPP which is released under MIT license.
4 * See file LICENSE.txt or go to
5 * https://github.com/JBenda/inkcpp for full license details.
6 */
7#pragma once
8
9#include "config.h"
10#include "system.h"
11
12#ifdef INK_ENABLE_STL
13# include <string>
14#endif
15
17namespace ink::runtime::internal
18{
19template<typename... Ts>
20constexpr size_t sizeof_largest_type()
21{
22 size_t ret = 0;
23 return ((ret = sizeof(Ts) > ret ? sizeof(Ts) : ret), ...);
24}
25
26template<unsigned int N, typename Arg, typename... Args>
27struct get_ith_type : get_ith_type<N - 1, Args...> {
28};
29
30template<typename Arg, typename... Args>
31struct get_ith_type<0, Arg, Args...> {
33 using type = Arg;
34};
35
36// constant and is_same from http://www.cppreference.com
37template<typename T, T v>
38struct constant {
39 static constexpr T value = v;
40 typedef T value_type;
41 typedef constant type; // using injected-class-name
42
43 constexpr operator value_type() const noexcept { return value; }
44
45 constexpr value_type operator()() const noexcept { return value; } // since c++14
46};
47
48struct false_type : constant<bool, false> {
49};
50
51struct true_type : constant<bool, true> {
52};
53
54template<typename B>
55true_type test_ptr_conv(const volatile B*);
56template<typename>
57false_type test_ptr_conv(const volatile void*);
58template<typename B, typename D>
59auto test_is_base_of(int) -> decltype(test_ptr_conv<B>(static_cast<D*>(nullptr)));
60
61// template<typename, typename> /// FIXME: needed?
62// auto test_is_base_of(...) -> true_type;
63
64template<class Base, class Derived>
65struct is_base_of : constant<bool, decltype(test_is_base_of<Base, Derived>(0))::value> {
66};
67
68template<class T, class U>
69struct is_same : false_type {
70};
71
72template<class T>
73struct is_same<T, T> : true_type {
74};
75
76template<typename T>
77struct is_pointer : false_type {
78};
79
80template<typename T>
81struct is_pointer<T*> : true_type {
82};
83
84template<class T>
85struct remove_cv {
86 typedef T type;
87};
88
89template<class T>
90struct remove_cv<const T> {
91 typedef T type;
92};
93
94template<class T>
95struct remove_cv<volatile T> {
96 typedef T type;
97};
98
99template<class T>
100struct remove_cv<const volatile T> {
101 typedef T type;
102};
103
104template<class T>
105struct remove_cvref {
106 typedef std::remove_cv_t<std::remove_reference_t<T>> type;
107};
108
109// == string testing (from me) ==
110
111template<typename T>
112struct is_string : false_type {
113};
114
115template<typename T>
116struct is_string<T&> : is_string<T> {
117};
118
119template<typename T>
120struct is_string<const T> : is_string<T> {
121};
122
123template<typename T>
124struct is_string<const T*> : is_string<T*> {
125};
126
127template<typename T>
128struct string_handler {
129};
130
131template<typename T>
132struct string_handler<const T> : string_handler<T> {
133};
134
135template<typename T>
136struct string_handler<const T*> : string_handler<T*> {
137};
138
139template<typename T>
140struct string_handler<T&> : string_handler<T> {
141};
142
143#define MARK_AS_STRING(TYPE, LEN, SRC) \
144 template<> \
145 struct is_string<TYPE> : constant<bool, true> { \
146 }; \
147 template<> \
148 struct string_handler<TYPE> { \
149 static size_t length(const TYPE& x) { return static_cast<size_t>(LEN); } \
150 static void src_copy(const TYPE& x, char* output) \
151 { \
152 [&output](const char* src) { \
153 while (*src != '\0') \
154 *(output++) = *(src++); \
155 *output = 0; \
156 }(SRC); \
157 } \
158 }
159
160inline size_t c_str_len(const char* c)
161{
162 const char* i = c;
163 while (*i != 0)
164 i++;
165 return i - c;
166}
167
168MARK_AS_STRING(char*, c_str_len(x), x);
169#ifdef INK_ENABLE_STL
170MARK_AS_STRING(std::string, x.size(), x.c_str());
171#endif
172#ifdef INK_ENABLE_UNREAL
173MARK_AS_STRING(FString, x.Len(), TCHAR_TO_UTF8(*x));
174#endif
175
176#undef MARK_AS_STRING
177
178// function_traits from https://functionalcpp.wordpress.com/2013/08/05/function-traits/
179
180template<class F>
181struct function_traits;
182
183// function pointer
184template<class R, class... Args>
185struct function_traits<R (*)(Args...)> : public function_traits<R(Args...)> {
186};
187
188template<class R, class... Args>
189struct function_traits<R(Args...)> {
190 using return_type = R;
191
192 static constexpr unsigned int arity = sizeof...(Args);
193
194 template<unsigned int N>
195 struct argument {
196 static_assert(N < arity, "error: invalid parameter index.");
197 using type = typename get_ith_type<N, Args...>::type;
198 };
199};
200
201// member function pointer
202template<class C, class R, class... Args>
203struct function_traits<R (C::*)(Args...)> : public function_traits<R(C&, Args...)> {
204};
205
206// const member function pointer
207template<class C, class R, class... Args>
208struct function_traits<R (C::*)(Args...) const> : public function_traits<R(C&, Args...)> {
209};
210
211// member object pointer
212template<class C, class R>
213struct function_traits<R(C::*)> : public function_traits<R(C&)> {
214};
215
216// functor
217template<class F>
218struct function_traits {
219private:
220 using call_type = function_traits<decltype(&F::operator())>;
221
222public:
223 using return_type = typename call_type::return_type;
224
225 static constexpr unsigned int arity = call_type::arity - 1;
226
227 template<unsigned int N>
228 struct argument {
229 static_assert(N < arity, "error: invalid parameter index.");
230 using type = typename call_type::template argument<N + 1>::type;
231 };
232};
233
234// from https://stackoverflow.com/questions/17424477/implementation-c14-make-integer-sequence
235// using aliases for cleaner syntax
236template<class T>
237using Invoke = typename T::type;
238
239template<unsigned...>
240struct seq {
241 using type = seq;
242};
243
244template<class S1, class S2>
245struct concat;
246
247template<unsigned... I1, unsigned... I2>
248struct concat<seq<I1...>, seq<I2...>> : seq<I1..., (sizeof...(I1) + I2)...> {
249};
250
251template<class S1, class S2>
252using Concat = Invoke<concat<S1, S2>>;
253
254template<unsigned N>
255struct gen_seq;
256template<unsigned N>
257using GenSeq = Invoke<gen_seq<N>>;
258
259template<unsigned N>
260struct gen_seq : Concat<GenSeq<N / 2>, GenSeq<N - N / 2>> {
261};
262
263template<>
264struct gen_seq<0> : seq<> {
265};
266
267template<>
268struct gen_seq<1> : seq<0> {
269};
270} // namespace ink::runtime::internal