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_reference {
106 typedef T type;
107};
108
109template<class T>
110struct remove_reference<T&> {
111 typedef T type;
112};
113
114template<class T>
115struct remove_reference<T&&> {
116 typedef T type;
117};
118
119template<class T>
120struct remove_cvref {
121 typedef typename remove_cv<typename remove_reference<T>::type>::type type;
122};
123
124// == string testing (from me) ==
125
126template<typename T>
127struct is_string : false_type {
128};
129
130template<typename T>
131struct is_string<T&> : is_string<T> {
132};
133
134template<typename T>
135struct is_string<const T> : is_string<T> {
136};
137
138template<typename T>
139struct is_string<const T*> : is_string<T*> {
140};
141
142template<typename T>
143struct string_handler {
144};
145
146template<typename T>
147struct string_handler<const T> : string_handler<T> {
148};
149
150template<typename T>
151struct string_handler<const T*> : string_handler<T*> {
152};
153
154template<typename T>
155struct string_handler<T&> : string_handler<T> {
156};
157
158#define MARK_AS_STRING(TYPE, LEN, SRC) \
159 template<> \
160 struct is_string<TYPE> : constant<bool, true> { \
161 }; \
162 template<> \
163 struct string_handler<TYPE> { \
164 static size_t length(const TYPE& x) { return static_cast<size_t>(LEN); } \
165 static void src_copy(const TYPE& x, char* output) \
166 { \
167 [&output](const char* src) { \
168 while (*src != '\0') \
169 *(output++) = *(src++); \
170 *output = 0; \
171 }(SRC); \
172 } \
173 }
174
175inline size_t c_str_len(const char* c)
176{
177 const char* i = c;
178 while (*i != 0)
179 i++;
180 return i - c;
181}
182
183MARK_AS_STRING(char*, c_str_len(x), x);
184#ifdef INK_ENABLE_STL
185MARK_AS_STRING(std::string, x.size(), x.c_str());
186#endif
187#ifdef INK_ENABLE_UNREAL
188MARK_AS_STRING(FString, x.Len(), TCHAR_TO_UTF8(*x));
189#endif
190
191#undef MARK_AS_STRING
192
193// function_traits from https://functionalcpp.wordpress.com/2013/08/05/function-traits/
194
195template<class F>
196struct function_traits;
197
198// function pointer
199template<class R, class... Args>
200struct function_traits<R (*)(Args...)> : public function_traits<R(Args...)> {
201};
202
203template<class R, class... Args>
204struct function_traits<R(Args...)> {
205 using return_type = R;
206
207 static constexpr unsigned int arity = sizeof...(Args);
208
209 template<unsigned int N>
210 struct argument {
211 static_assert(N < arity, "error: invalid parameter index.");
212 using type = typename get_ith_type<N, Args...>::type;
213 };
214};
215
216// member function pointer
217template<class C, class R, class... Args>
218struct function_traits<R (C::*)(Args...)> : public function_traits<R(C&, Args...)> {
219};
220
221// const member function pointer
222template<class C, class R, class... Args>
223struct function_traits<R (C::*)(Args...) const> : public function_traits<R(C&, Args...)> {
224};
225
226// member object pointer
227template<class C, class R>
228struct function_traits<R(C::*)> : public function_traits<R(C&)> {
229};
230
231// functor
232template<class F>
233struct function_traits {
234private:
235 using call_type = function_traits<decltype(&F::operator())>;
236
237public:
238 using return_type = typename call_type::return_type;
239
240 static constexpr unsigned int arity = call_type::arity - 1;
241
242 template<unsigned int N>
243 struct argument {
244 static_assert(N < arity, "error: invalid parameter index.");
245 using type = typename call_type::template argument<N + 1>::type;
246 };
247};
248
249// from https://stackoverflow.com/questions/17424477/implementation-c14-make-integer-sequence
250// using aliases for cleaner syntax
251template<class T>
252using Invoke = typename T::type;
253
254template<unsigned...>
255struct seq {
256 using type = seq;
257};
258
259template<class S1, class S2>
260struct concat;
261
262template<unsigned... I1, unsigned... I2>
263struct concat<seq<I1...>, seq<I2...>> : seq<I1..., (sizeof...(I1) + I2)...> {
264};
265
266template<class S1, class S2>
267using Concat = Invoke<concat<S1, S2>>;
268
269template<unsigned N>
270struct gen_seq;
271template<unsigned N>
272using GenSeq = Invoke<gen_seq<N>>;
273
274template<unsigned N>
275struct gen_seq : Concat<GenSeq<N / 2>, GenSeq<N - N / 2>> {
276};
277
278template<>
279struct gen_seq<0> : seq<> {
280};
281
282template<>
283struct gen_seq<1> : seq<0> {
284};
285} // namespace ink::runtime::internal