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