1 // The MIT License (MIT)
2 
3 // Copyright (c) 2013-2016 Rapptz, ThePhD and contributors
4 
5 // Permission is hereby granted, free of charge, to any person obtaining a copy of
6 // this software and associated documentation files (the "Software"), to deal in
7 // the Software without restriction, including without limitation the rights to
8 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 // the Software, and to permit persons to whom the Software is furnished to do so,
10 // subject to the following conditions:
11 
12 // The above copyright notice and this permission notice shall be included in all
13 // copies or substantial portions of the Software.
14 
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 
22 #ifndef SOL_TRAITS_HPP
23 #define SOL_TRAITS_HPP
24 
25 #include "tuple.hpp"
26 #include "bind_traits.hpp"
27 #include <type_traits>
28 #include <memory>
29 #include <functional>
30 
31 namespace sol {
32 	template<std::size_t I>
33 	using index_value = std::integral_constant<std::size_t, I>;
34 
35 	namespace meta {
36 		template<typename T>
37 		struct identity { typedef T type; };
38 
39 		template<typename T>
40 		using identity_t = typename identity<T>::type;
41 
42 		template<typename... Args>
43 		struct is_tuple : std::false_type { };
44 
45 		template<typename... Args>
46 		struct is_tuple<std::tuple<Args...>> : std::true_type { };
47 
48 		template <typename T>
49 		struct is_builtin_type : std::integral_constant<bool, std::is_arithmetic<T>::value || std::is_pointer<T>::value || std::is_array<T>::value> {};
50 
51 		template<typename T>
52 		struct unwrapped {
53 			typedef T type;
54 		};
55 
56 		template<typename T>
57 		struct unwrapped<std::reference_wrapper<T>> {
58 			typedef T type;
59 		};
60 
61 		template<typename T>
62 		using unwrapped_t = typename unwrapped<T>::type;
63 
64 		template <typename T>
65 		struct unwrap_unqualified : unwrapped<unqualified_t<T>> {};
66 
67 		template <typename T>
68 		using unwrap_unqualified_t = typename unwrap_unqualified<T>::type;
69 
70 		template<typename T>
71 		struct remove_member_pointer;
72 
73 		template<typename R, typename T>
74 		struct remove_member_pointer<R T::*> {
75 			typedef R type;
76 		};
77 
78 		template<typename R, typename T>
79 		struct remove_member_pointer<R T::* const> {
80 			typedef R type;
81 		};
82 
83 		template<typename T>
84 		using remove_member_pointer_t = remove_member_pointer<T>;
85 
86 		template<template<typename...> class Templ, typename T>
87 		struct is_specialization_of : std::false_type { };
88 		template<typename... T, template<typename...> class Templ>
89 		struct is_specialization_of<Templ, Templ<T...>> : std::true_type { };
90 
91 		template<class T, class...>
92 		struct all_same : std::true_type { };
93 
94 		template<class T, class U, class... Args>
95 		struct all_same<T, U, Args...> : std::integral_constant <bool, std::is_same<T, U>::value && all_same<T, Args...>::value> { };
96 
97 		template<class T, class...>
98 		struct any_same : std::false_type { };
99 
100 		template<class T, class U, class... Args>
101 		struct any_same<T, U, Args...> : std::integral_constant <bool, std::is_same<T, U>::value || any_same<T, Args...>::value> { };
102 
103 		template<typename T>
104 		using invoke_t = typename T::type;
105 
106 		template<bool B>
107 		using boolean = std::integral_constant<bool, B>;
108 
109 		template<typename T>
110 		using neg = boolean<!T::value>;
111 
112 		template<typename Condition, typename Then, typename Else>
113 		using condition = std::conditional_t<Condition::value, Then, Else>;
114 
115 		template<typename... Args>
116 		struct all : boolean<true> {};
117 
118 		template<typename T, typename... Args>
119 		struct all<T, Args...> : condition<T, all<Args...>, boolean<false>> {};
120 
121 		template<typename... Args>
122 		struct any : boolean<false> {};
123 
124 		template<typename T, typename... Args>
125 		struct any<T, Args...> : condition<T, boolean<true>, any<Args...>> {};
126 
127 		enum class enable_t {
128 			_
129 		};
130 
131 		constexpr const auto enabler = enable_t::_;
132 
133 		template<bool value, typename T = void>
134 		using disable_if_t = std::enable_if_t<!value, T>;
135 
136 		template<typename... Args>
137 		using enable = std::enable_if_t<all<Args...>::value, enable_t>;
138 
139 		template<typename... Args>
140 		using disable = std::enable_if_t<neg<all<Args...>>::value, enable_t>;
141 
142 		template<typename... Args>
143 		using disable_any = std::enable_if_t<neg<any<Args...>>::value, enable_t>;
144 
145 		template<typename V, typename... Vs>
146 		struct find_in_pack_v : boolean<false> { };
147 
148 		template<typename V, typename Vs1, typename... Vs>
149 		struct find_in_pack_v<V, Vs1, Vs...> : any<boolean<(V::value == Vs1::value)>, find_in_pack_v<V, Vs...>> { };
150 
151 		namespace meta_detail {
152 			template<std::size_t I, typename T, typename... Args>
153 			struct index_in_pack : std::integral_constant<std::size_t, SIZE_MAX> { };
154 
155 			template<std::size_t I, typename T, typename T1, typename... Args>
156 			struct index_in_pack<I, T, T1, Args...> : std::conditional_t<std::is_same<T, T1>::value, std::integral_constant<std::ptrdiff_t, I>, index_in_pack<I + 1, T, Args...>> { };
157 		}
158 
159 		template<typename T, typename... Args>
160 		struct index_in_pack : meta_detail::index_in_pack<0, T, Args...> { };
161 
162 		template<typename T, typename List>
163 		struct index_in : meta_detail::index_in_pack<0, T, List> { };
164 
165 		template<typename T, typename... Args>
166 		struct index_in<T, types<Args...>> : meta_detail::index_in_pack<0, T, Args...> { };
167 
168 		template<std::size_t I, typename... Args>
169 		struct at_in_pack {};
170 
171 		template<std::size_t I, typename... Args>
172 		using at_in_pack_t = typename at_in_pack<I, Args...>::type;
173 
174 		template<std::size_t I, typename Arg, typename... Args>
175 		struct at_in_pack<I, Arg, Args...> : std::conditional<I == 0, Arg, at_in_pack_t<I - 1, Args...>> {};
176 
177 		template<typename Arg, typename... Args>
178 		struct at_in_pack<0, Arg, Args...> { typedef Arg type; };
179 
180 		namespace meta_detail {
181 			template<std::size_t Limit, std::size_t I, template<typename...> class Pred, typename... Ts>
182 			struct count_for_pack : std::integral_constant<std::size_t, 0> {};
183 			template<std::size_t Limit, std::size_t I, template<typename...> class Pred, typename T, typename... Ts>
184 			struct count_for_pack<Limit, I, Pred, T, Ts...> : std::conditional_t < sizeof...(Ts) == 0 || Limit < 2,
185 				std::integral_constant<std::size_t, I + static_cast<std::size_t>(Limit != 0 && Pred<T>::value)>,
186 				count_for_pack<Limit - 1, I + static_cast<std::size_t>(Pred<T>::value), Pred, Ts...>
187 			> { };
188 			template<std::size_t I, template<typename...> class Pred, typename... Ts>
189 			struct count_2_for_pack : std::integral_constant<std::size_t, 0> {};
190 			template<std::size_t I, template<typename...> class Pred, typename T, typename U, typename... Ts>
191 			struct count_2_for_pack<I, Pred, T, U, Ts...> : std::conditional_t<sizeof...(Ts) == 0,
192 				std::integral_constant<std::size_t, I + static_cast<std::size_t>(Pred<T>::value)>,
193 				count_2_for_pack<I + static_cast<std::size_t>(Pred<T>::value), Pred, Ts...>
194 			> { };
195 		} // meta_detail
196 
197 		template<template<typename...> class Pred, typename... Ts>
198 		struct count_for_pack : meta_detail::count_for_pack<sizeof...(Ts), 0, Pred, Ts...> { };
199 
200 		template<template<typename...> class Pred, typename List>
201 		struct count_for;
202 
203 		template<template<typename...> class Pred, typename... Args>
204 		struct count_for<Pred, types<Args...>> : count_for_pack<Pred, Args...> {};
205 
206 		template<std::size_t Limit, template<typename...> class Pred, typename... Ts>
207 		struct count_for_to_pack : meta_detail::count_for_pack<Limit, 0, Pred, Ts...> { };
208 
209 		template<template<typename...> class Pred, typename... Ts>
210 		struct count_2_for_pack : meta_detail::count_2_for_pack<0, Pred, Ts...> { };
211 
212 		template<typename... Args>
213 		struct return_type {
214 			typedef std::tuple<Args...> type;
215 		};
216 
217 		template<typename T>
218 		struct return_type<T> {
219 			typedef T type;
220 		};
221 
222 		template<>
223 		struct return_type<> {
224 			typedef void type;
225 		};
226 
227 		template <typename... Args>
228 		using return_type_t = typename return_type<Args...>::type;
229 
230 		namespace meta_detail {
231 			template <typename> struct always_true : std::true_type {};
232 			struct is_invokable_tester {
233 				template <typename Fun, typename... Args>
234 				always_true<decltype(std::declval<Fun>()(std::declval<Args>()...))> static test(int);
235 				template <typename...>
236 				std::false_type static test(...);
237 			};
238 		} // meta_detail
239 
240 		template <typename T>
241 		struct is_invokable;
242 		template <typename Fun, typename... Args>
243 		struct is_invokable<Fun(Args...)> : decltype(meta_detail::is_invokable_tester::test<Fun, Args...>(0)) {};
244 
245 		namespace meta_detail {
246 
247 			template<typename T, bool isclass = std::is_class<unqualified_t<T>>::value>
248 			struct is_callable : std::is_function<std::remove_pointer_t<T>> {};
249 
250 			template<typename T>
251 			struct is_callable<T, true> {
252 				using yes = char;
253 				using no = struct { char s[2]; };
254 
operator ()sol::meta::meta_detail::is_callable::F255 				struct F { void operator()() {}; };
256 				struct Derived : T, F {};
257 				template<typename U, U> struct Check;
258 
259 				template<typename V>
260 				static no test(Check<void (F::*)(), &V::operator()>*);
261 
262 				template<typename>
263 				static yes test(...);
264 
265 				static const bool value = sizeof(test<Derived>(0)) == sizeof(yes);
266 			};
267 
268 			struct has_begin_end_impl {
269 				template<typename T, typename U = unqualified_t<T>,
270 					typename B = decltype(std::declval<U&>().begin()),
271 					typename E = decltype(std::declval<U&>().end())>
272 					static std::true_type test(int);
273 
274 				template<typename...>
275 				static std::false_type test(...);
276 			};
277 
278 			struct has_key_value_pair_impl {
279 				template<typename T, typename U = unqualified_t<T>,
280 					typename V = typename U::value_type,
281 					typename F = decltype(std::declval<V&>().first),
282 					typename S = decltype(std::declval<V&>().second)>
283 					static std::true_type test(int);
284 
285 				template<typename...>
286 				static std::false_type test(...);
287 			};
288 
289 			template <typename T, typename U = T, typename = decltype(std::declval<T&>() < std::declval<U&>())>
290 			std::true_type supports_op_less_test(const T&);
291 			std::false_type supports_op_less_test(...);
292 			template <typename T, typename U = T, typename = decltype(std::declval<T&>() == std::declval<U&>())>
293 			std::true_type supports_op_equal_test(const T&);
294 			std::false_type supports_op_equal_test(...);
295 			template <typename T, typename U = T, typename = decltype(std::declval<T&>() <= std::declval<U&>())>
296 			std::true_type supports_op_less_equal_test(const T&);
297 			std::false_type supports_op_less_equal_test(...);
298 
299 		} // meta_detail
300 
301 		template <typename T>
302 		using supports_op_less = decltype(meta_detail::supports_op_less_test(std::declval<T&>()));
303 		template <typename T>
304 		using supports_op_equal = decltype(meta_detail::supports_op_equal_test(std::declval<T&>()));
305 		template <typename T>
306 		using supports_op_less_equal = decltype(meta_detail::supports_op_less_equal_test(std::declval<T&>()));
307 
308 		template<typename T>
309 		struct is_callable : boolean<meta_detail::is_callable<T>::value> {};
310 
311 		template<typename T>
312 		struct has_begin_end : decltype(meta_detail::has_begin_end_impl::test<T>(0)) {};
313 
314 		template<typename T>
315 		struct has_key_value_pair : decltype(meta_detail::has_key_value_pair_impl::test<T>(0)) {};
316 
317 		template <typename T>
318 		using is_string_constructible = any<std::is_same<unqualified_t<T>, const char*>, std::is_same<unqualified_t<T>, char>, std::is_same<unqualified_t<T>, std::string>, std::is_same<unqualified_t<T>, std::initializer_list<char>>>;
319 
320 		template <typename T>
321 		using is_c_str = any<
322 			std::is_same<std::decay_t<unqualified_t<T>>, const char*>,
323 			std::is_same<std::decay_t<unqualified_t<T>>, char*>,
324 			std::is_same<unqualified_t<T>, std::string>
325 		>;
326 
327 		template <typename T>
328 		struct is_move_only : all<
329 			neg<std::is_reference<T>>,
330 			neg<std::is_copy_constructible<unqualified_t<T>>>,
331 			std::is_move_constructible<unqualified_t<T>>
332 		> {};
333 
334 		template <typename T>
335 		using is_not_move_only = neg<is_move_only<T>>;
336 
337 		namespace meta_detail {
338 			template <typename T, meta::disable<meta::is_specialization_of<std::tuple, meta::unqualified_t<T>>> = meta::enabler>
force_tuple(T && x)339 			decltype(auto) force_tuple(T&& x) {
340 				return std::forward_as_tuple(std::forward<T>(x));
341 			}
342 
343 			template <typename T, meta::enable<meta::is_specialization_of<std::tuple, meta::unqualified_t<T>>> = meta::enabler>
force_tuple(T && x)344 			decltype(auto) force_tuple(T&& x) {
345 				return std::forward<T>(x);
346 			}
347 		} // meta_detail
348 
349 		template <typename... X>
tuplefy(X &&...x)350 		decltype(auto) tuplefy(X&&... x) {
351 			return std::tuple_cat(meta_detail::force_tuple(std::forward<X>(x))...);
352 		}
353 	} // meta
354 	namespace detail {
355 		template <std::size_t I, typename Tuple>
forward_get(Tuple && tuple)356 		decltype(auto) forward_get(Tuple&& tuple) {
357 			return std::forward<meta::tuple_element_t<I, Tuple>>(std::get<I>(tuple));
358 		}
359 
360 		template <std::size_t... I, typename Tuple>
forward_tuple_impl(std::index_sequence<I...>,Tuple && tuple)361 		auto forward_tuple_impl(std::index_sequence<I...>, Tuple&& tuple) -> decltype(std::tuple<decltype(forward_get<I>(tuple))...>(forward_get<I>(tuple)...)) {
362 			return std::tuple<decltype(forward_get<I>(tuple))...>(std::move(std::get<I>(tuple))...);
363 		}
364 
365 		template <typename Tuple>
forward_tuple(Tuple && tuple)366 		auto forward_tuple(Tuple&& tuple) {
367 			auto x = forward_tuple_impl(std::make_index_sequence<std::tuple_size<meta::unqualified_t<Tuple>>::value>(), std::forward<Tuple>(tuple));
368 			return x;
369 		}
370 
371 		template<typename T>
unwrap(T && item)372 		auto unwrap(T&& item) -> decltype(std::forward<T>(item)) {
373 			return std::forward<T>(item);
374 		}
375 
376 		template<typename T>
unwrap(std::reference_wrapper<T> arg)377 		T& unwrap(std::reference_wrapper<T> arg) {
378 			return arg.get();
379 		}
380 
381 		template<typename T>
deref(T && item)382 		auto deref(T&& item) -> decltype(std::forward<T>(item)) {
383 			return std::forward<T>(item);
384 		}
385 
386 		template<typename T>
deref(T * item)387 		inline T& deref(T* item) {
388 			return *item;
389 		}
390 
391 		template<typename T, typename Dx>
deref(std::unique_ptr<T,Dx> & item)392 		inline std::add_lvalue_reference_t<T> deref(std::unique_ptr<T, Dx>& item) {
393 			return *item;
394 		}
395 
396 		template<typename T>
deref(std::shared_ptr<T> & item)397 		inline std::add_lvalue_reference_t<T> deref(std::shared_ptr<T>& item) {
398 			return *item;
399 		}
400 
401 		template<typename T, typename Dx>
deref(const std::unique_ptr<T,Dx> & item)402 		inline std::add_lvalue_reference_t<T> deref(const std::unique_ptr<T, Dx>& item) {
403 			return *item;
404 		}
405 
406 		template<typename T>
deref(const std::shared_ptr<T> & item)407 		inline std::add_lvalue_reference_t<T> deref(const std::shared_ptr<T>& item) {
408 			return *item;
409 		}
410 
411 		template<typename T>
ptr(T & val)412 		inline T* ptr(T& val) {
413 			return std::addressof(val);
414 		}
415 
416 		template<typename T>
ptr(std::reference_wrapper<T> val)417 		inline T* ptr(std::reference_wrapper<T> val) {
418 			return std::addressof(val.get());
419 		}
420 
421 		template<typename T>
ptr(T * val)422 		inline T* ptr(T* val) {
423 			return val;
424 		}
425 	} // detail
426 } // sol
427 
428 #endif // SOL_TRAITS_HPP
429