| 1 | //===----------------------------------------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #ifndef SORTABLE_HELPERS_H |
| 10 | #define SORTABLE_HELPERS_H |
| 11 | |
| 12 | #include <cstddef> |
| 13 | #include <type_traits> |
| 14 | |
| 15 | #include "test_macros.h" |
| 16 | |
| 17 | #if TEST_STD_VER > 17 |
| 18 | #include <compare> |
| 19 | #include <iterator> |
| 20 | #include "test_iterators.h" |
| 21 | #endif |
| 22 | |
| 23 | struct TrivialSortable { |
| 24 | int value; |
| 25 | TEST_CONSTEXPR TrivialSortable() : value(0) {} |
| 26 | TEST_CONSTEXPR TrivialSortable(int v) : value(v) {} |
| 27 | friend TEST_CONSTEXPR bool operator<(const TrivialSortable& a, const TrivialSortable& b) { |
| 28 | return a.value / 10 < b.value / 10; |
| 29 | } |
| 30 | static TEST_CONSTEXPR bool less(const TrivialSortable& a, const TrivialSortable& b) { |
| 31 | return a.value < b.value; |
| 32 | } |
| 33 | }; |
| 34 | |
| 35 | struct NonTrivialSortable { |
| 36 | int value; |
| 37 | TEST_CONSTEXPR NonTrivialSortable() : value(0) {} |
| 38 | TEST_CONSTEXPR NonTrivialSortable(int v) : value(v) {} |
| 39 | TEST_CONSTEXPR NonTrivialSortable(const NonTrivialSortable& rhs) : value(rhs.value) {} |
| 40 | TEST_CONSTEXPR_CXX14 NonTrivialSortable& operator=(const NonTrivialSortable& rhs) { value = rhs.value; return *this; } |
| 41 | friend TEST_CONSTEXPR bool operator<(const NonTrivialSortable& a, const NonTrivialSortable& b) { |
| 42 | return a.value / 10 < b.value / 10; |
| 43 | } |
| 44 | static TEST_CONSTEXPR bool less(const NonTrivialSortable& a, const NonTrivialSortable& b) { |
| 45 | return a.value < b.value; |
| 46 | } |
| 47 | }; |
| 48 | |
| 49 | |
| 50 | struct TrivialSortableWithComp { |
| 51 | int value; |
| 52 | TEST_CONSTEXPR TrivialSortableWithComp() : value(0) {} |
| 53 | TEST_CONSTEXPR TrivialSortableWithComp(int v) : value(v) {} |
| 54 | struct Comparator { |
| 55 | TEST_CONSTEXPR bool operator()(const TrivialSortableWithComp& a, const TrivialSortableWithComp& b) const { |
| 56 | return a.value / 10 < b.value / 10; |
| 57 | } |
| 58 | }; |
| 59 | static TEST_CONSTEXPR bool less(const TrivialSortableWithComp& a, const TrivialSortableWithComp& b) { |
| 60 | return a.value < b.value; |
| 61 | } |
| 62 | }; |
| 63 | |
| 64 | struct NonTrivialSortableWithComp { |
| 65 | int value; |
| 66 | TEST_CONSTEXPR NonTrivialSortableWithComp() : value(0) {} |
| 67 | TEST_CONSTEXPR NonTrivialSortableWithComp(int v) : value(v) {} |
| 68 | TEST_CONSTEXPR NonTrivialSortableWithComp(const NonTrivialSortableWithComp& rhs) : value(rhs.value) {} |
| 69 | TEST_CONSTEXPR_CXX14 NonTrivialSortableWithComp& operator=(const NonTrivialSortableWithComp& rhs) { value = rhs.value; return *this; } |
| 70 | struct Comparator { |
| 71 | TEST_CONSTEXPR bool operator()(const NonTrivialSortableWithComp& a, const NonTrivialSortableWithComp& b) const { |
| 72 | return a.value / 10 < b.value / 10; |
| 73 | } |
| 74 | }; |
| 75 | static TEST_CONSTEXPR bool less(const NonTrivialSortableWithComp& a, const NonTrivialSortableWithComp& b) { |
| 76 | return a.value < b.value; |
| 77 | } |
| 78 | }; |
| 79 | |
| 80 | static_assert(std::is_trivially_copyable<TrivialSortable>::value, "" ); |
| 81 | static_assert(std::is_trivially_copyable<TrivialSortableWithComp>::value, "" ); |
| 82 | static_assert(!std::is_trivially_copyable<NonTrivialSortable>::value, "" ); |
| 83 | static_assert(!std::is_trivially_copyable<NonTrivialSortableWithComp>::value, "" ); |
| 84 | |
| 85 | #if TEST_STD_VER > 17 |
| 86 | struct TracedCopy { |
| 87 | int copied = 0; |
| 88 | int data = 0; |
| 89 | |
| 90 | constexpr TracedCopy() = default; |
| 91 | constexpr TracedCopy(int i) : data(i) {} |
| 92 | constexpr TracedCopy(const TracedCopy& other) : copied(other.copied + 1), data(other.data) {} |
| 93 | |
| 94 | constexpr TracedCopy(TracedCopy&& other) = delete; |
| 95 | constexpr TracedCopy& operator=(TracedCopy&& other) = delete; |
| 96 | |
| 97 | constexpr TracedCopy& operator=(const TracedCopy& other) { |
| 98 | copied = other.copied + 1; |
| 99 | data = other.data; |
| 100 | return *this; |
| 101 | } |
| 102 | |
| 103 | constexpr bool copiedOnce() const { return copied == 1; } |
| 104 | |
| 105 | constexpr bool operator==(const TracedCopy& o) const { return data == o.data; } |
| 106 | constexpr auto operator<=>(const TracedCopy& o) const { return data <=> o.data; } |
| 107 | }; |
| 108 | |
| 109 | template <class Iter> |
| 110 | struct NonBorrowedRange { |
| 111 | int* data_; |
| 112 | std::size_t size_; |
| 113 | |
| 114 | // TODO: some algorithms calls std::__copy |
| 115 | // std::__copy(contiguous_iterator<int*>, sentinel_wrapper<contiguous_iterator<int*>>, contiguous_iterator<int*>) doesn't seem to work. |
| 116 | // It seems that it unwraps contiguous_iterator<int*> into int*, and then it failed because there is no == between int* and |
| 117 | // sentinel_wrapper<contiguous_iterator<int*>> |
| 118 | using Sent = std::conditional_t<std::contiguous_iterator<Iter>, Iter, sentinel_wrapper<Iter>>; |
| 119 | |
| 120 | constexpr NonBorrowedRange(int* d, std::size_t s) : data_{d}, size_{s} {} |
| 121 | |
| 122 | constexpr Iter begin() const { return Iter{data_}; }; |
| 123 | constexpr Sent end() const { return Sent{Iter{data_ + size_}}; }; |
| 124 | }; |
| 125 | #endif // TEST_STD_VER > 17 |
| 126 | |
| 127 | #endif // SORTABLE_HELPERS_H |
| 128 | |