1 /////////////////////////////////////////////////////////////////////////////// 2 // Copyright (c) Electronic Arts Inc. All rights reserved. 3 /////////////////////////////////////////////////////////////////////////////// 4 5 6 #ifndef EASTL_UTILITY_H 7 #define EASTL_UTILITY_H 8 9 10 #include <EASTL/internal/config.h> 11 #include <EASTL/type_traits.h> 12 #include <EASTL/iterator.h> 13 #include <EASTL/functional.h> 14 #include <EASTL/internal/move_help.h> 15 #include <EABase/eahave.h> 16 17 #include <EASTL/internal/integer_sequence.h> 18 #include <EASTL/internal/tuple_fwd_decls.h> 19 #include <EASTL/internal/in_place_t.h> 20 #include <EASTL/internal/piecewise_construct_t.h> 21 22 #ifdef _MSC_VER 23 #pragma warning(push) // VC++ generates a bogus warning that you cannot code away. 24 #pragma warning(disable: 4619) // There is no warning number 'number'. 25 #pragma warning(disable: 4217) // Member template functions cannot be used for copy-assignment or copy-construction. 26 #pragma warning(disable: 4512) // 'class' : assignment operator could not be generated. // This disabling would best be put elsewhere. 27 #endif 28 29 #if defined(EA_PRAGMA_ONCE_SUPPORTED) 30 #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. 31 #endif 32 33 34 35 namespace eastl 36 { 37 38 /// swap 39 /// 40 /// Assigns the contents of a to b and the contents of b to a. 41 /// A temporary instance of type T is created and destroyed 42 /// in the process. 43 /// 44 /// This function is used by numerous other algorithms, and as 45 /// such it may in some cases be feasible and useful for the user 46 /// to implement an override version of this function which is 47 /// more efficient in some way. 48 /// 49 50 template <typename T> swap(T & a,T & b)51 inline void swap(T& a, T& b) EA_NOEXCEPT_IF(eastl::is_nothrow_move_constructible<T>::value && eastl::is_nothrow_move_assignable<T>::value) 52 { 53 T temp(EASTL_MOVE(a)); // EASTL_MOVE uses EASTL::move when available, else is a no-op. 54 a = EASTL_MOVE(b); 55 b = EASTL_MOVE(temp); 56 } 57 58 59 /// is_swappable 60 /// 61 /// Determines if two types can be swapped via the swap function. This determines 62 /// only if there is a swap function that matches the types and not if the assignments 63 /// within the swap implementation are valid. 64 /// Returns false for pre-C++11 compilers that don't support decltype. 65 /// 66 /// This is a type trait, but it's not currently found within <type_traits.h>, 67 /// as it's dependent on the swap algorithm, which is at a higher level than 68 /// type traits. 69 /// 70 /// Example usage: 71 /// static_assert(is_swappable<int>::value, "int should be swappable"); 72 /// 73 #if defined(EA_COMPILER_NO_DECLTYPE) 74 #define EASTL_TYPE_TRAIT_is_swappable_CONFORMANCE 0 75 76 template <typename> 77 struct is_swappable 78 : public eastl::false_type {}; 79 #else 80 #define EASTL_TYPE_TRAIT_is_swappable_CONFORMANCE 1 81 82 // We declare this version of 'eastl::swap' to make compile-time existance checks for swap functions possible. 83 // 84 #if EASTL_VARIADIC_TEMPLATES_ENABLED 85 eastl::unused swap(eastl::argument_sink, eastl::argument_sink); 86 #else 87 // Compilers that do not support variadic templates suffer from a bug with variable arguments list that 88 // causes the construction of aligned types in unaligned memory. To prevent the aligned type construction we 89 // accept the parameters by reference. 90 eastl::unused swap(eastl::argument_sink&, eastl::argument_sink&); 91 #endif 92 93 template <typename T> 94 struct is_swappable 95 : public integral_constant<bool, !eastl::is_same<decltype(swap(eastl::declval<T&>(), eastl::declval<T&>())), eastl::unused>::value> {}; // Don't prefix swap with eastl:: as we want to allow user-defined swaps via argument-dependent lookup. 96 #endif 97 98 #if EASTL_VARIABLE_TEMPLATES_ENABLED 99 template <class T> 100 EA_CONSTEXPR bool is_swappable_v = is_swappable<T>::value; 101 #endif 102 103 104 105 /// is_nothrow_swappable 106 /// 107 /// Evaluates to true if is_swappable, and swap is a nothrow function. 108 /// returns false for pre-C++11 compilers that don't support nothrow. 109 /// 110 /// This is a type trait, but it's not currently found within <type_traits.h>, 111 /// as it's dependent on the swap algorithm, which is at a higher level than 112 /// type traits. 113 /// 114 #define EASTL_TYPE_TRAIT_is_nothrow_swappable_CONFORMANCE EASTL_TYPE_TRAIT_is_swappable_CONFORMANCE 115 116 template <typename T> 117 struct is_nothrow_swappable_helper_noexcept_wrapper 118 { const static bool value = noexcept(swap(eastl::declval<T&>(), eastl::declval<T&>())); }; 119 120 template <typename T, bool> 121 struct is_nothrow_swappable_helper 122 : public eastl::integral_constant<bool, is_nothrow_swappable_helper_noexcept_wrapper<T>::value> {}; // Don't prefix swap with eastl:: as we want to allow user-defined swaps via argument-dependent lookup. 123 124 template <typename T> 125 struct is_nothrow_swappable_helper<T, false> 126 : public eastl::false_type {}; 127 128 template <typename T> 129 struct is_nothrow_swappable 130 : public eastl::is_nothrow_swappable_helper<T, eastl::is_swappable<T>::value> {}; 131 132 #if EASTL_VARIABLE_TEMPLATES_ENABLED 133 template <class T> 134 EA_CONSTEXPR bool is_nothrow_swappable_v = is_nothrow_swappable<T>::value; 135 #endif 136 137 138 139 /// is_swappable_with 140 /// 141 /// 142 template <typename T, typename U, bool OneTypeIsVoid = (eastl::is_void<T>::value || eastl::is_void<U>::value)> 143 struct is_swappable_with_helper 144 { 145 // Don't prefix swap with eastl:: as we want to allow user-defined swaps via argument-dependent lookup. 146 static const bool value = 147 !eastl::is_same<decltype(swap(eastl::declval<T>(), eastl::declval<U>())), eastl::unused>::value && 148 !eastl::is_same<decltype(swap(eastl::declval<U>(), eastl::declval<T>())), eastl::unused>::value; 149 }; 150 151 template <typename T, typename U> 152 struct is_swappable_with_helper<T,U, true> { static const bool value = false; }; 153 154 template<typename T, typename U> 155 struct is_swappable_with 156 : public eastl::bool_constant<is_swappable_with_helper<T, U>::value> {}; 157 158 #if EASTL_VARIABLE_TEMPLATES_ENABLED 159 template <class T, class U> 160 EA_CONSTEXPR bool is_swappable_with_v = is_swappable_with<T, U>::value; 161 #endif 162 163 164 165 /// is_nothrow_swappable_with 166 /// 167 /// 168 #if defined(EA_COMPILER_NO_DECLTYPE) || defined(EA_COMPILER_NO_NOEXCEPT) 169 #define EASTL_TYPE_TRAIT_is_nothrow_swappable_with_CONFORMANCE 0 170 template <typename T, typename U> 171 struct is_nothrow_swappable_with_helper { static const bool value = false; }; 172 #else 173 #define EASTL_TYPE_TRAIT_is_nothrow_swappable_with_CONFORMANCE 1 174 template <typename T, typename U, bool OneTypeIsVoid = (eastl::is_void<T>::value || eastl::is_void<U>::value)> 175 struct is_nothrow_swappable_with_helper 176 { 177 // Don't prefix swap with eastl:: as we want to allow user-defined swaps via argument-dependent lookup. 178 static const bool value = noexcept(swap(eastl::declval<T>(), eastl::declval<U>())) && 179 noexcept(swap(eastl::declval<U>(), eastl::declval<T>())); 180 }; 181 182 template <typename T, typename U> 183 struct is_nothrow_swappable_with_helper<T,U, true> { static const bool value = false; }; 184 #endif 185 186 template <typename T, typename U> 187 struct is_nothrow_swappable_with : public eastl::bool_constant<is_nothrow_swappable_with_helper<T, U>::value> {}; 188 189 #if EASTL_VARIABLE_TEMPLATES_ENABLED 190 template <class T, class U> 191 EA_CONSTEXPR bool is_nothrow_swappable_with_v = is_nothrow_swappable_with<T, U>::value; 192 #endif 193 194 195 196 // iter_swap helper functions 197 // 198 template <bool bTypesAreEqual> 199 struct iter_swap_impl 200 { 201 // Handles the false case, where *a and *b are different types. 202 template <typename ForwardIterator1, typename ForwardIterator2> 203 static void iter_swap(ForwardIterator1 a, ForwardIterator2 b) 204 { 205 typedef typename eastl::iterator_traits<ForwardIterator1>::value_type value_type_a; 206 207 value_type_a temp(EASTL_MOVE(*a)); // EASTL_MOVE uses EASTL::move when available, else is a no-op. 208 *a = EASTL_MOVE(*b); 209 *b = EASTL_MOVE(temp); 210 } 211 }; 212 213 template <> 214 struct iter_swap_impl<true> 215 { 216 template <typename ForwardIterator1, typename ForwardIterator2> 217 static void iter_swap(ForwardIterator1 a, ForwardIterator2 b) 218 { 219 swap(*a, *b); // Don't prefix swap with eastl:: as we want to allow user-defined swaps via argument-dependent lookup. 220 } 221 }; 222 223 224 /// iter_swap 225 /// 226 /// Swaps the values of the elements the given iterators are pointing to. 227 /// 228 /// Equivalent to swap(*a, *b), though the user can provide an override to 229 /// iter_swap that is independent of an override which may exist for swap. 230 /// 231 /// We provide a version of iter_swap which uses swap when the swapped types 232 /// are equal but a manual implementation otherwise. We do this because the 233 /// C++ standard defect report says that iter_swap(a, b) must be implemented 234 /// as swap(*a, *b) when possible. 235 /// 236 template <typename ForwardIterator1, typename ForwardIterator2> 237 inline void iter_swap(ForwardIterator1 a, ForwardIterator2 b) 238 { 239 typedef typename eastl::iterator_traits<ForwardIterator1>::value_type value_type_a; 240 typedef typename eastl::iterator_traits<ForwardIterator2>::value_type value_type_b; 241 typedef typename eastl::iterator_traits<ForwardIterator1>::reference reference_a; 242 typedef typename eastl::iterator_traits<ForwardIterator2>::reference reference_b; 243 244 eastl::iter_swap_impl<eastl::type_and<eastl::is_same<value_type_a, value_type_b>::value, eastl::is_same<value_type_a&, reference_a>::value, eastl::is_same<value_type_b&, reference_b>::value >::value >::iter_swap(a, b); 245 } 246 247 248 249 /// swap_ranges 250 /// 251 /// Swaps each of the elements in the range [first1, last1) with the 252 /// corresponding element in the range [first2, first2 + (last1 - first1)). 253 /// 254 /// Effects: For each nonnegative integer n < (last1 - first1), 255 /// performs: swap(*(first1 + n), *(first2 + n)). 256 /// 257 /// Requires: The two ranges [first1, last1) and [first2, first2 + (last1 - first1)) 258 /// shall not overlap. 259 /// 260 /// Returns: first2 + (last1 - first1). That is, returns the end of the second range. 261 /// 262 /// Complexity: Exactly 'last1 - first1' swaps. 263 /// 264 template <typename ForwardIterator1, typename ForwardIterator2> 265 inline ForwardIterator2 266 swap_ranges(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2) 267 { 268 for(; first1 != last1; ++first1, ++first2) 269 iter_swap(first1, first2); // Don't prefix swap with eastl:: as we want to allow user-defined swaps via argument-dependent lookup. 270 return first2; 271 } 272 273 274 /// swap 275 /// 276 /// C++11 array swap 277 /// http://en.cppreference.com/w/cpp/algorithm/swap 278 /// 279 template <typename T, size_t N> 280 inline void 281 swap(T (&a)[N], T (&b)[N]) EA_NOEXCEPT_IF(eastl::is_nothrow_swappable<T>::value) 282 { 283 eastl::swap_ranges(a, a + N, b); 284 } 285 286 287 /// exchange 288 /// 289 /// Replaces the value of the first argument with the new value provided. 290 /// The return value is the previous value of first argument. 291 /// 292 /// http://en.cppreference.com/w/cpp/utility/exchange 293 /// 294 template <typename T, typename U = T> 295 inline T exchange(T& obj, U&& new_value) 296 { 297 T old_value = eastl::move(obj); 298 obj = eastl::forward<U>(new_value); 299 return old_value; 300 } 301 302 303 /// as_const 304 /// 305 /// Converts a 'T&' into a 'const T&' which simplifies calling const functions on non-const objects. 306 /// 307 /// http://en.cppreference.com/w/cpp/utility/as_const 308 /// 309 /// C++ proposal paper: 310 /// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4380.html 311 /// 312 template <class T> 313 EA_CONSTEXPR typename eastl::add_const<T>::type& as_const(T& t) EA_NOEXCEPT 314 { return t; } 315 316 // The C++17 forbids 'eastl::as_const' from accepting rvalues. Passing an rvalue reference to 'eastl::as_const' 317 // generates an 'const T&' or const lvalue reference to a temporary object. 318 template <class T> 319 void as_const(const T&&) = delete; 320 321 322 /////////////////////////////////////////////////////////////////////// 323 /// rel_ops 324 /// 325 /// rel_ops allow the automatic generation of operators !=, >, <=, >= from 326 /// just operators == and <. These are intentionally in the rel_ops namespace 327 /// so that they don't conflict with other similar operators. To use these 328 /// operators, add "using namespace std::rel_ops;" to an appropriate place in 329 /// your code, usually right in the function that you need them to work. 330 /// In fact, you will very likely have collision problems if you put such 331 /// using statements anywhere other than in the .cpp file like so and may 332 /// also have collisions when you do, as the using statement will affect all 333 /// code in the module. You need to be careful about use of rel_ops. 334 /// 335 namespace rel_ops 336 { 337 template <typename T> 338 inline bool operator!=(const T& x, const T& y) 339 { return !(x == y); } 340 341 template <typename T> 342 inline bool operator>(const T& x, const T& y) 343 { return (y < x); } 344 345 template <typename T> 346 inline bool operator<=(const T& x, const T& y) 347 { return !(y < x); } 348 349 template <typename T> 350 inline bool operator>=(const T& x, const T& y) 351 { return !(x < y); } 352 } 353 354 355 /////////////////////////////////////////////////////////////////////// 356 /// pair_first_construct 357 /// 358 /// Disambiguates when a user is requesting the 'single first element' pair constructor. 359 /// 360 struct pair_first_construct_t {}; 361 EA_CONSTEXPR pair_first_construct_t pair_first_construct = pair_first_construct_t(); 362 363 364 /////////////////////////////////////////////////////////////////////// 365 /// pair 366 /// 367 /// Implements a simple pair, just like the C++ std::pair. 368 /// 369 template <typename T1, typename T2> 370 struct pair 371 { 372 typedef T1 first_type; 373 typedef T2 second_type; 374 typedef pair<T1, T2> this_type; 375 376 T1 first; 377 T2 second; 378 379 template <typename TT1 = T1, 380 typename TT2 = T2, 381 class = eastl::enable_if_t<eastl::is_default_constructible_v<TT1> && 382 eastl::is_default_constructible_v<TT2>>> 383 EA_CONSTEXPR pair() 384 : first(), second() 385 { 386 } 387 388 #if EASTL_ENABLE_PAIR_FIRST_ELEMENT_CONSTRUCTOR 389 template <typename TT2 = T2, typename = eastl::enable_if_t<eastl::is_default_constructible_v<TT2>>> 390 EA_CPP14_CONSTEXPR pair(const T1& x) 391 : first(x), second() 392 { 393 } 394 395 // GCC has a bug with overloading rvalue and lvalue function templates. 396 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54425 397 // 398 // error: 'eastl::pair<T1, T2>::pair(T1&&) [with T1 = const int&; T2 = const int&]' cannot be overloaded 399 // error: with 'eastl::pair<T1, T2>::pair(const T1&) [with T1 = const int&; T2 = const int&]' 400 #if !defined(EA_COMPILER_GNUC) 401 template <typename TT2 = T2, typename = eastl::enable_if_t<eastl::is_default_constructible_v<TT2>>> 402 EA_CPP14_CONSTEXPR pair(T1&& x) 403 : first(eastl::move(x)), second() 404 { 405 } 406 #endif 407 #endif 408 409 410 // NOTE(rparolin): 411 // This is a workaround to a compiler intrinic bug which fails to correctly identify a nested class using 412 // non-static data member initialization as default constructible. 413 // 414 // See bug submitted to LLVM for more details. 415 // https://bugs.llvm.org/show_bug.cgi?id=38374 416 #if !defined(EA_COMPILER_CLANG) 417 template<typename T> 418 using single_pair_ctor_sfinae = eastl::enable_if_t<eastl::is_default_constructible_v<T>>; 419 #else 420 template<typename> 421 using single_pair_ctor_sfinae = void; 422 #endif 423 424 template <typename TT2 = T2, typename = single_pair_ctor_sfinae<TT2>> 425 EA_CPP14_CONSTEXPR pair(pair_first_construct_t, const T1& x) 426 : first(x), second() 427 { 428 } 429 430 // GCC has a bug with overloading rvalue and lvalue function templates. 431 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54425 432 // 433 // error: 'eastl::pair<T1, T2>::pair(T1&&) [with T1 = const int&; T2 = const int&]' cannot be overloaded 434 // error: with 'eastl::pair<T1, T2>::pair(const T1&) [with T1 = const int&; T2 = const int&]' 435 #if !defined(EA_COMPILER_GNUC) 436 template <typename TT2 = T2, typename = single_pair_ctor_sfinae<TT2>> 437 EA_CPP14_CONSTEXPR pair(pair_first_construct_t, T1&& x) 438 : first(eastl::move(x)), second() 439 { 440 } 441 #endif 442 443 template < 444 typename TT1 = T1, 445 typename TT2 = T2, 446 class = eastl::enable_if_t<eastl::is_copy_constructible_v<TT1> && eastl::is_copy_constructible_v<TT2>>> 447 EA_CPP14_CONSTEXPR pair(const T1& x, const T2& y) 448 : first(x), second(y) 449 { 450 } 451 452 EA_CPP14_CONSTEXPR pair(pair&& p) = default; 453 EA_CPP14_CONSTEXPR pair(const pair&) = default; 454 455 template < 456 typename U, 457 typename V, 458 class = eastl::enable_if_t<eastl::is_convertible_v<const U&, T1> && eastl::is_convertible_v<const V&, T2>>> 459 EA_CPP14_CONSTEXPR pair(const pair<U, V>& p) 460 : first(p.first), second(p.second) 461 { 462 } 463 464 template <typename U, 465 typename V, 466 typename = eastl::enable_if_t<eastl::is_convertible_v<U, T1> && eastl::is_convertible_v<V, T2>>> 467 EA_CPP14_CONSTEXPR pair(U&& u, V&& v) 468 : first(eastl::forward<U>(u)), second(eastl::forward<V>(v)) 469 { 470 } 471 472 template <typename U, typename = eastl::enable_if_t<eastl::is_convertible_v<U, T1>>> 473 EA_CPP14_CONSTEXPR pair(U&& x, const T2& y) 474 : first(eastl::forward<U>(x)), second(y) 475 { 476 } 477 478 template <typename V, typename = eastl::enable_if_t<eastl::is_convertible_v<V, T2>>> 479 EA_CPP14_CONSTEXPR pair(const T1& x, V&& y) 480 : first(x), second(eastl::forward<V>(y)) 481 { 482 } 483 484 template <typename U, 485 typename V, 486 typename = eastl::enable_if_t<eastl::is_convertible_v<U, T1> && eastl::is_convertible_v<V, T2>>> 487 EA_CPP14_CONSTEXPR pair(pair<U, V>&& p) 488 : first(eastl::forward<U>(p.first)), second(eastl::forward<V>(p.second)) 489 { 490 } 491 492 // Initializes first with arguments of types Args1... obtained by forwarding the elements of first_args and 493 // initializes second with arguments of types Args2... obtained by forwarding the elements of second_args. 494 template <class... Args1, 495 class... Args2, 496 typename = eastl::enable_if_t<eastl::is_constructible_v<first_type, Args1&&...> && 497 eastl::is_constructible_v<second_type, Args2&&...>>> 498 pair(eastl::piecewise_construct_t pwc, eastl::tuple<Args1...> first_args, eastl::tuple<Args2...> second_args) 499 : pair(pwc, 500 eastl::move(first_args), 501 eastl::move(second_args), 502 eastl::make_index_sequence<sizeof...(Args1)>(), 503 eastl::make_index_sequence<sizeof...(Args2)>()) 504 { 505 } 506 507 private: 508 // NOTE(rparolin): Internal constructor used to expand the index_sequence required to expand the tuple elements. 509 template <class... Args1, class... Args2, size_t... I1, size_t... I2> 510 pair(eastl::piecewise_construct_t, 511 eastl::tuple<Args1...> first_args, 512 eastl::tuple<Args2...> second_args, 513 eastl::index_sequence<I1...>, 514 eastl::index_sequence<I2...>) 515 : first(eastl::forward<Args1>(eastl::get<I1>(first_args))...) 516 , second(eastl::forward<Args2>(eastl::get<I2>(second_args))...) 517 { 518 } 519 520 public: 521 pair& operator=(const pair& p) 522 EA_NOEXCEPT_IF(eastl::is_nothrow_copy_assignable_v<T1>&& eastl::is_nothrow_copy_assignable_v<T2>) 523 { 524 first = p.first; 525 second = p.second; 526 return *this; 527 } 528 529 template <typename U, 530 typename V, 531 typename = eastl::enable_if_t<eastl::is_convertible_v<U, T1> && eastl::is_convertible_v<V, T2>>> 532 pair& operator=(const pair<U, V>& p) 533 { 534 first = p.first; 535 second = p.second; 536 return *this; 537 } 538 539 pair& operator=(pair&& p) 540 EA_NOEXCEPT_IF(eastl::is_nothrow_move_assignable_v<T1>&& eastl::is_nothrow_move_assignable_v<T2>) 541 { 542 first = eastl::forward<T1>(p.first); 543 second = eastl::forward<T2>(p.second); 544 return *this; 545 } 546 547 template <typename U, 548 typename V, 549 typename = eastl::enable_if_t<eastl::is_convertible_v<U, T1> && eastl::is_convertible_v<V, T2>>> 550 pair& operator=(pair<U, V>&& p) 551 { 552 first = eastl::forward<U>(p.first); 553 second = eastl::forward<V>(p.second); 554 return *this; 555 } 556 557 void swap(pair& p) EA_NOEXCEPT_IF(eastl::is_nothrow_swappable_v<T1>&& eastl::is_nothrow_swappable_v<T2>) 558 { 559 eastl::iter_swap(&first, &p.first); 560 eastl::iter_swap(&second, &p.second); 561 } 562 }; 563 564 #define EASTL_PAIR_CONFORMANCE 1 565 566 567 568 /// use_self 569 /// 570 /// operator()(x) simply returns x. Used in sets, as opposed to maps. 571 /// This is a template policy implementation; it is an alternative to 572 /// the use_first template implementation. 573 /// 574 /// The existance of use_self may seem odd, given that it does nothing, 575 /// but these kinds of things are useful, virtually required, for optimal 576 /// generic programming. 577 /// 578 template <typename T> 579 struct use_self // : public unary_function<T, T> // Perhaps we want to make it a subclass of unary_function. 580 { 581 typedef T result_type; 582 583 const T& operator()(const T& x) const 584 { return x; } 585 }; 586 587 /// use_first 588 /// 589 /// operator()(x) simply returns x.first. Used in maps, as opposed to sets. 590 /// This is a template policy implementation; it is an alternative to 591 /// the use_self template implementation. This is the same thing as the 592 /// SGI SGL select1st utility. 593 /// 594 template <typename Pair> 595 struct use_first 596 { 597 typedef Pair argument_type; 598 typedef typename Pair::first_type result_type; 599 600 const result_type& operator()(const Pair& x) const 601 { return x.first; } 602 }; 603 604 /// use_second 605 /// 606 /// operator()(x) simply returns x.second. 607 /// This is the same thing as the SGI SGL select2nd utility 608 /// 609 template <typename Pair> 610 struct use_second // : public unary_function<Pair, typename Pair::second_type> // Perhaps we want to make it a subclass of unary_function. 611 { 612 typedef Pair argument_type; 613 typedef typename Pair::second_type result_type; 614 615 const result_type& operator()(const Pair& x) const 616 { return x.second; } 617 }; 618 619 620 621 622 623 /////////////////////////////////////////////////////////////////////// 624 // global operators 625 /////////////////////////////////////////////////////////////////////// 626 627 template <typename T1, typename T2> 628 EA_CPP14_CONSTEXPR inline bool operator==(const pair<T1, T2>& a, const pair<T1, T2>& b) 629 { 630 return ((a.first == b.first) && (a.second == b.second)); 631 } 632 633 634 template <typename T1, typename T2> 635 EA_CPP14_CONSTEXPR inline bool operator<(const pair<T1, T2>& a, const pair<T1, T2>& b) 636 { 637 // Note that we use only operator < in this expression. Otherwise we could 638 // use the simpler: return (a.m1 == b.m1) ? (a.m2 < b.m2) : (a.m1 < b.m1); 639 // The user can write a specialization for this operator to get around this 640 // in cases where the highest performance is required. 641 return ((a.first < b.first) || (!(b.first < a.first) && (a.second < b.second))); 642 } 643 644 645 template <typename T1, typename T2> 646 EA_CPP14_CONSTEXPR inline bool operator!=(const pair<T1, T2>& a, const pair<T1, T2>& b) 647 { 648 return !(a == b); 649 } 650 651 652 template <typename T1, typename T2> 653 EA_CPP14_CONSTEXPR inline bool operator>(const pair<T1, T2>& a, const pair<T1, T2>& b) 654 { 655 return b < a; 656 } 657 658 659 template <typename T1, typename T2> 660 EA_CPP14_CONSTEXPR inline bool operator>=(const pair<T1, T2>& a, const pair<T1, T2>& b) 661 { 662 return !(a < b); 663 } 664 665 666 template <typename T1, typename T2> 667 EA_CPP14_CONSTEXPR inline bool operator<=(const pair<T1, T2>& a, const pair<T1, T2>& b) 668 { 669 return !(b < a); 670 } 671 672 673 674 675 /////////////////////////////////////////////////////////////////////// 676 /// make_pair / make_pair_ref 677 /// 678 /// make_pair is the same as std::make_pair specified by the C++ standard. 679 /// If you look at the C++ standard, you'll see that it specifies T& instead of T. 680 /// However, it has been determined that the C++ standard is incorrect and has 681 /// flagged it as a defect (http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#181). 682 /// In case you feel that you want a more efficient version that uses references, 683 /// we provide the make_pair_ref function below, though C++11 move support 684 /// makes that no longer necessary. 685 /// 686 /// Note: You don't usually need to use make_pair in order to make a pair. 687 /// The following code is equivalent, and the latter avoids one more level of inlining: 688 /// return make_pair(charPtr, charPtr); 689 /// return pair<char*, char*>(charPtr, charPtr); 690 /// 691 template <typename T1, typename T2> 692 EA_CPP14_CONSTEXPR inline pair<typename eastl::remove_reference_wrapper<typename eastl::decay<T1>::type>::type, 693 typename eastl::remove_reference_wrapper<typename eastl::decay<T2>::type>::type> 694 make_pair(T1&& a, T2&& b) 695 { 696 typedef typename eastl::remove_reference_wrapper<typename eastl::decay<T1>::type>::type T1Type; 697 typedef typename eastl::remove_reference_wrapper<typename eastl::decay<T2>::type>::type T2Type; 698 699 return eastl::pair<T1Type, T2Type>(eastl::forward<T1>(a), eastl::forward<T2>(b)); 700 } 701 702 703 // Without the following, VC++ fails to compile code like this: pair<const char*, int> p = eastl::make_pair<const char*, int>("hello", 0); 704 // We define a const reference version alternative to the above. "hello" is of type char const(&)[6] (array of 6 const chars), 705 // but VC++ decays it to const char* and allows this make_pair to be called with that. VC++ fails below with make_pair("hello", "people") 706 // because you can't assign arrays and until we have a better solution we just disable this make_pair specialization for when T1 or T2 707 // are of type char const(&)[]. 708 #if defined(_MSC_VER) 709 template <typename T1, typename T2> 710 EA_CPP14_CONSTEXPR inline pair<T1, T2> make_pair( 711 const T1& a, 712 const T2& b, 713 typename eastl::enable_if<!eastl::is_array<T1>::value && !eastl::is_array<T2>::value>::type* = 0) 714 { 715 return eastl::pair<T1, T2>(a, b); 716 } 717 #endif 718 719 // For backwards compatibility 720 template <typename T1, typename T2> 721 EA_CPP14_CONSTEXPR inline pair<typename eastl::remove_reference_wrapper<typename eastl::decay<T1>::type>::type, 722 typename eastl::remove_reference_wrapper<typename eastl::decay<T2>::type>::type> 723 make_pair_ref(T1&& a, T2&& b) 724 { 725 typedef typename eastl::remove_reference_wrapper<typename eastl::decay<T1>::type>::type T1Type; 726 typedef typename eastl::remove_reference_wrapper<typename eastl::decay<T2>::type>::type T2Type; 727 728 return eastl::pair<T1Type, T2Type>(eastl::forward<T1>(a), eastl::forward<T2>(b)); 729 } 730 731 #if EASTL_TUPLE_ENABLED 732 733 template <typename T1, typename T2> 734 class tuple_size<pair<T1, T2>> : public integral_constant<size_t, 2> 735 { 736 }; 737 738 template <typename T1, typename T2> 739 class tuple_size<const pair<T1, T2>> : public integral_constant<size_t, 2> 740 { 741 }; 742 743 template <typename T1, typename T2> 744 class tuple_element<0, pair<T1, T2>> 745 { 746 public: 747 typedef T1 type; 748 }; 749 750 template <typename T1, typename T2> 751 class tuple_element<1, pair<T1, T2>> 752 { 753 public: 754 typedef T2 type; 755 }; 756 757 template <typename T1, typename T2> 758 class tuple_element<0, const pair<T1, T2>> 759 { 760 public: 761 typedef const T1 type; 762 }; 763 764 template <typename T1, typename T2> 765 class tuple_element<1, const pair<T1, T2>> 766 { 767 public: 768 typedef const T2 type; 769 }; 770 771 template <size_t I> 772 struct GetPair; 773 774 template <> 775 struct GetPair<0> 776 { 777 template <typename T1, typename T2> 778 static EA_CONSTEXPR T1& getInternal(pair<T1, T2>& p) 779 { 780 return p.first; 781 } 782 783 template <typename T1, typename T2> 784 static EA_CONSTEXPR const T1& getInternal(const pair<T1, T2>& p) 785 { 786 return p.first; 787 } 788 789 template <typename T1, typename T2> 790 static EA_CONSTEXPR T1&& getInternal(pair<T1, T2>&& p) 791 { 792 return forward<T1>(p.first); 793 } 794 }; 795 796 template <> 797 struct GetPair<1> 798 { 799 template <typename T1, typename T2> 800 static EA_CONSTEXPR T2& getInternal(pair<T1, T2>& p) 801 { 802 return p.second; 803 } 804 805 template <typename T1, typename T2> 806 static EA_CONSTEXPR const T2& getInternal(const pair<T1, T2>& p) 807 { 808 return p.second; 809 } 810 811 template <typename T1, typename T2> 812 static EA_CONSTEXPR T2&& getInternal(pair<T1, T2>&& p) 813 { 814 return forward<T2>(p.second); 815 } 816 }; 817 818 template <size_t I, typename T1, typename T2> 819 tuple_element_t<I, pair<T1, T2>>& get(pair<T1, T2>& p) 820 { 821 return GetPair<I>::getInternal(p); 822 } 823 824 template <size_t I, typename T1, typename T2> 825 const tuple_element_t<I, pair<T1, T2>>& get(const pair<T1, T2>& p) 826 { 827 return GetPair<I>::getInternal(p); 828 } 829 830 template <size_t I, typename T1, typename T2> 831 tuple_element_t<I, pair<T1, T2>>&& get(pair<T1, T2>&& p) 832 { 833 return GetPair<I>::getInternal(move(p)); 834 } 835 836 #endif // EASTL_TUPLE_ENABLED 837 838 839 } // namespace eastl 840 841 #ifdef _MSC_VER 842 #pragma warning(pop) 843 #endif 844 845 846 #endif // Header include guard 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862