1 // MPark.Variant
2 //
3 // Copyright Michael Park, 2015-2017
4 //
5 // Distributed under the Boost Software License, Version 1.0.
6 // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
7 
8 #ifndef MPARK_LIB_HPP
9 #define MPARK_LIB_HPP
10 
11 #include <memory>
12 #include <functional>
13 #include <type_traits>
14 #include <utility>
15 
16 #include "config.hpp"
17 
18 #define RETURN(...)                                          \
19   noexcept(noexcept(__VA_ARGS__)) -> decltype(__VA_ARGS__) { \
20     return __VA_ARGS__;                                      \
21   }
22 
23 namespace mpark {
24   namespace lib {
25     template <typename T>
26     struct identity { using type = T; };
27 
28     inline namespace cpp14 {
29       template <typename T, std::size_t N>
30       struct array {
operator []mpark::lib::cpp14::array31         constexpr const T &operator[](std::size_t index) const {
32           return data[index];
33         }
34 
35         T data[N == 0 ? 1 : N];
36       };
37 
38       template <typename T>
39       using add_pointer_t = typename std::add_pointer<T>::type;
40 
41       template <typename... Ts>
42       using common_type_t = typename std::common_type<Ts...>::type;
43 
44       template <typename T>
45       using decay_t = typename std::decay<T>::type;
46 
47       template <bool B, typename T = void>
48       using enable_if_t = typename std::enable_if<B, T>::type;
49 
50       template <typename T>
51       using remove_const_t = typename std::remove_const<T>::type;
52 
53       template <typename T>
54       using remove_reference_t = typename std::remove_reference<T>::type;
55 
56       template <typename T>
forward(remove_reference_t<T> & t)57       inline constexpr T &&forward(remove_reference_t<T> &t) noexcept {
58         return static_cast<T &&>(t);
59       }
60 
61       template <typename T>
forward(remove_reference_t<T> && t)62       inline constexpr T &&forward(remove_reference_t<T> &&t) noexcept {
63         static_assert(!std::is_lvalue_reference<T>::value,
64                       "can not forward an rvalue as an lvalue");
65         return static_cast<T &&>(t);
66       }
67 
68       template <typename T>
move(T && t)69       inline constexpr remove_reference_t<T> &&move(T &&t) noexcept {
70         return static_cast<remove_reference_t<T> &&>(t);
71       }
72 
73 #ifdef MPARK_INTEGER_SEQUENCE
74       using std::integer_sequence;
75       using std::index_sequence;
76       using std::make_index_sequence;
77       using std::index_sequence_for;
78 #else
79       template <typename T, T... Is>
80       struct integer_sequence {
81         using value_type = T;
sizempark::lib::cpp14::integer_sequence82         static constexpr std::size_t size() noexcept { return sizeof...(Is); }
83       };
84 
85       template <std::size_t... Is>
86       using index_sequence = integer_sequence<std::size_t, Is...>;
87 
88       template <typename Lhs, typename Rhs>
89       struct make_index_sequence_concat;
90 
91       template <std::size_t... Lhs, std::size_t... Rhs>
92       struct make_index_sequence_concat<index_sequence<Lhs...>,
93                                         index_sequence<Rhs...>>
94           : identity<index_sequence<Lhs..., (sizeof...(Lhs) + Rhs)...>> {};
95 
96       template <std::size_t N>
97       struct make_index_sequence_impl;
98 
99       template <std::size_t N>
100       using make_index_sequence = typename make_index_sequence_impl<N>::type;
101 
102       template <std::size_t N>
103       struct make_index_sequence_impl
104           : make_index_sequence_concat<make_index_sequence<N / 2>,
105                                        make_index_sequence<N - (N / 2)>> {};
106 
107       template <>
108       struct make_index_sequence_impl<0> : identity<index_sequence<>> {};
109 
110       template <>
111       struct make_index_sequence_impl<1> : identity<index_sequence<0>> {};
112 
113       template <typename... Ts>
114       using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
115 #endif
116 
117       // <functional>
118 #ifdef MPARK_TRANSPARENT_OPERATORS
119       using equal_to = std::equal_to<>;
120 #else
121       struct equal_to {
122         template <typename Lhs, typename Rhs>
123         inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const
124           RETURN(lib::forward<Lhs>(lhs) == lib::forward<Rhs>(rhs))
125       };
126 #endif
127 
128 #ifdef MPARK_TRANSPARENT_OPERATORS
129       using not_equal_to = std::not_equal_to<>;
130 #else
131       struct not_equal_to {
132         template <typename Lhs, typename Rhs>
133         inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const
134           RETURN(lib::forward<Lhs>(lhs) != lib::forward<Rhs>(rhs))
135       };
136 #endif
137 
138 #ifdef MPARK_TRANSPARENT_OPERATORS
139       using less = std::less<>;
140 #else
141       struct less {
142         template <typename Lhs, typename Rhs>
143         inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const
144           RETURN(lib::forward<Lhs>(lhs) < lib::forward<Rhs>(rhs))
145       };
146 #endif
147 
148 #ifdef MPARK_TRANSPARENT_OPERATORS
149       using greater = std::greater<>;
150 #else
151       struct greater {
152         template <typename Lhs, typename Rhs>
153         inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const
154           RETURN(lib::forward<Lhs>(lhs) > lib::forward<Rhs>(rhs))
155       };
156 #endif
157 
158 #ifdef MPARK_TRANSPARENT_OPERATORS
159       using less_equal = std::less_equal<>;
160 #else
161       struct less_equal {
162         template <typename Lhs, typename Rhs>
163         inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const
164           RETURN(lib::forward<Lhs>(lhs) <= lib::forward<Rhs>(rhs))
165       };
166 #endif
167 
168 #ifdef MPARK_TRANSPARENT_OPERATORS
169       using greater_equal = std::greater_equal<>;
170 #else
171       struct greater_equal {
172         template <typename Lhs, typename Rhs>
173         inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const
174           RETURN(lib::forward<Lhs>(lhs) >= lib::forward<Rhs>(rhs))
175       };
176 #endif
177     }  // namespace cpp14
178 
179     inline namespace cpp17 {
180 
181       // <type_traits>
182       template <bool B>
183       using bool_constant = std::integral_constant<bool, B>;
184 
185       template <typename...>
186       struct voider : identity<void> {};
187 
188       template <typename... Ts>
189       using void_t = typename voider<Ts...>::type;
190 
191       namespace detail {
192         namespace swappable {
193 
194           using std::swap;
195 
196           template <typename T>
197           struct is_swappable {
198             private:
199             template <typename U,
200                       typename = decltype(swap(std::declval<U &>(),
201                                                std::declval<U &>()))>
202             inline static std::true_type test(int);
203 
204             template <typename U>
205             inline static std::false_type test(...);
206 
207             public:
208             static constexpr bool value = decltype(test<T>(0))::value;
209           };
210 
211           template <typename T, bool = is_swappable<T>::value>
212           struct is_nothrow_swappable {
213             static constexpr bool value =
214                 noexcept(swap(std::declval<T &>(), std::declval<T &>()));
215           };
216 
217           template <typename T>
218           struct is_nothrow_swappable<T, false> : std::false_type {};
219 
220         }  // namespace swappable
221       }  // namespace detail
222 
223       using detail::swappable::is_swappable;
224       using detail::swappable::is_nothrow_swappable;
225 
226       // <functional>
227 #ifdef _MSC_VER
228 #pragma warning(push)
229 #pragma warning(disable : 4100)
230 #endif
231       template <typename F, typename... As>
232       inline constexpr auto invoke(F &&f, As &&... as)
233           RETURN(lib::forward<F>(f)(lib::forward<As>(as)...))
234 #ifdef _MSC_VER
235 #pragma warning(pop)
236 #endif
237 
238       template <typename B, typename T, typename D>
239       inline constexpr auto invoke(T B::*pmv, D &&d)
240           RETURN(lib::forward<D>(d).*pmv)
241 
242       template <typename Pmv, typename Ptr>
243       inline constexpr auto invoke(Pmv pmv, Ptr &&ptr)
244           RETURN((*lib::forward<Ptr>(ptr)).*pmv)
245 
246       template <typename B, typename T, typename D, typename... As>
247       inline constexpr auto invoke(T B::*pmf, D &&d, As &&... as)
248           RETURN((lib::forward<D>(d).*pmf)(lib::forward<As>(as)...))
249 
250       template <typename Pmf, typename Ptr, typename... As>
251       inline constexpr auto invoke(Pmf pmf, Ptr &&ptr, As &&... as)
252           RETURN(((*lib::forward<Ptr>(ptr)).*pmf)(lib::forward<As>(as)...))
253 
254       namespace detail {
255 
256         template <typename Void, typename, typename...>
257         struct invoke_result {};
258 
259         template <typename F, typename... Args>
260         struct invoke_result<void_t<decltype(lib::invoke(
261                                  std::declval<F>(), std::declval<Args>()...))>,
262                              F,
263                              Args...>
264             : identity<decltype(
265                   lib::invoke(std::declval<F>(), std::declval<Args>()...))> {};
266 
267       }  // namespace detail
268 
269       template <typename F, typename... Args>
270       using invoke_result = detail::invoke_result<void, F, Args...>;
271 
272       template <typename F, typename... Args>
273       using invoke_result_t = typename invoke_result<F, Args...>::type;
274 
275       namespace detail {
276 
277         template <typename Void, typename, typename...>
278         struct is_invocable : std::false_type {};
279 
280         template <typename F, typename... Args>
281         struct is_invocable<void_t<invoke_result_t<F, Args...>>, F, Args...>
282             : std::true_type {};
283 
284         template <typename Void, typename, typename, typename...>
285         struct is_invocable_r : std::false_type {};
286 
287         template <typename R, typename F, typename... Args>
288         struct is_invocable_r<void_t<invoke_result_t<F, Args...>>,
289                               R,
290                               F,
291                               Args...>
292             : std::is_convertible<invoke_result_t<F, Args...>, R> {};
293 
294       }  // namespace detail
295 
296       template <typename F, typename... Args>
297       using is_invocable = detail::is_invocable<void, F, Args...>;
298 
299       template <typename R, typename F, typename... Args>
300       using is_invocable_r = detail::is_invocable_r<void, R, F, Args...>;
301 
302       // <memory>
303 #ifdef MPARK_BUILTIN_ADDRESSOF
304       template <typename T>
addressof(T & arg)305       inline constexpr T *addressof(T &arg) {
306         return __builtin_addressof(arg);
307       }
308 #else
309       namespace detail {
310 
311         namespace has_addressof_impl {
312 
313           struct fail;
314 
315           template <typename T>
316           inline fail operator&(T &&);
317 
318           template <typename T>
impl()319           inline static constexpr bool impl() {
320             return (std::is_class<T>::value || std::is_union<T>::value) &&
321                    !std::is_same<decltype(&std::declval<T &>()), fail>::value;
322           }
323 
324         }  // namespace has_addressof_impl
325 
326         template <typename T>
327         using has_addressof = bool_constant<has_addressof_impl::impl<T>()>;
328 
329         template <typename T>
addressof(T & arg,std::true_type)330         inline constexpr T *addressof(T &arg, std::true_type) {
331           return std::addressof(arg);
332         }
333 
334         template <typename T>
addressof(T & arg,std::false_type)335         inline constexpr T *addressof(T &arg, std::false_type) {
336           return &arg;
337         }
338 
339       }  // namespace detail
340 
341       template <typename T>
addressof(T & arg)342       inline constexpr T *addressof(T &arg) {
343         return detail::addressof(arg, detail::has_addressof<T>{});
344       }
345 #endif
346 
347       template <typename T>
348       inline constexpr T *addressof(const T &&) = delete;
349 
350     }  // namespace cpp17
351 
352     template <typename T>
353     struct remove_all_extents : identity<T> {};
354 
355     template <typename T, std::size_t N>
356     struct remove_all_extents<array<T, N>> : remove_all_extents<T> {};
357 
358     template <typename T>
359     using remove_all_extents_t = typename remove_all_extents<T>::type;
360 
361     template <std::size_t N>
362     using size_constant = std::integral_constant<std::size_t, N>;
363 
364     template <std::size_t I, typename T>
365     struct indexed_type : size_constant<I>, identity<T> {};
366 
367     template <bool... Bs>
368     using all = std::is_same<integer_sequence<bool, true, Bs...>,
369                              integer_sequence<bool, Bs..., true>>;
370 
371 #ifdef MPARK_TYPE_PACK_ELEMENT
372     template <std::size_t I, typename... Ts>
373     using type_pack_element_t = __type_pack_element<I, Ts...>;
374 #else
375     template <std::size_t I, typename... Ts>
376     struct type_pack_element_impl {
377       private:
378       template <typename>
379       struct set;
380 
381       template <std::size_t... Is>
382       struct set<index_sequence<Is...>> : indexed_type<Is, Ts>... {};
383 
384       template <typename T>
385       inline static std::enable_if<true, T> impl(indexed_type<I, T>);
386 
387       inline static std::enable_if<false> impl(...);
388 
389       public:
390       using type = decltype(impl(set<index_sequence_for<Ts...>>{}));
391     };
392 
393     template <std::size_t I, typename... Ts>
394     using type_pack_element = typename type_pack_element_impl<I, Ts...>::type;
395 
396     template <std::size_t I, typename... Ts>
397     using type_pack_element_t = typename type_pack_element<I, Ts...>::type;
398 #endif
399 
400 #ifdef MPARK_TRIVIALITY_TYPE_TRAITS
401     using std::is_trivially_copy_constructible;
402     using std::is_trivially_move_constructible;
403     using std::is_trivially_copy_assignable;
404     using std::is_trivially_move_assignable;
405 #else
406     template <typename T>
407     struct is_trivially_copy_constructible
408         : bool_constant<
409               std::is_copy_constructible<T>::value && __has_trivial_copy(T)> {};
410 
411     template <typename T>
412     struct is_trivially_move_constructible : bool_constant<__is_trivial(T)> {};
413 
414     template <typename T>
415     struct is_trivially_copy_assignable
416         : bool_constant<
417               std::is_copy_assignable<T>::value && __has_trivial_assign(T)> {};
418 
419     template <typename T>
420     struct is_trivially_move_assignable : bool_constant<__is_trivial(T)> {};
421 #endif
422 
423     template <typename T, bool>
424     struct dependent_type : T {};
425 
426     template <typename Is, std::size_t J>
427     struct push_back;
428 
429     template <typename Is, std::size_t J>
430     using push_back_t = typename push_back<Is, J>::type;
431 
432     template <std::size_t... Is, std::size_t J>
433     struct push_back<index_sequence<Is...>, J> {
434       using type = index_sequence<Is..., J>;
435     };
436 
437   }  // namespace lib
438 }  // namespace mpark
439 
440 #undef RETURN
441 
442 #endif  // MPARK_LIB_HPP
443