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 LIBCXX_TEST_SUPPORT_BOOLEAN_TESTABLE_H 10 #define LIBCXX_TEST_SUPPORT_BOOLEAN_TESTABLE_H 11 12 #include "test_macros.h" 13 14 #include <iterator> 15 #include <utility> 16 17 #if TEST_STD_VER > 17 18 19 struct BooleanTestable { 20 constexpr operator bool() const { return value_; } 21 22 friend constexpr BooleanTestable operator==(const BooleanTestable& lhs, const BooleanTestable& rhs) { 23 return lhs.value_ == rhs.value_; 24 } 25 26 friend constexpr BooleanTestable operator!=(const BooleanTestable& lhs, const BooleanTestable& rhs) { 27 return lhs.value_ != rhs.value_; 28 } 29 30 constexpr BooleanTestable&& operator!() && { 31 value_ = !value_; 32 return std::move(*this); 33 } 34 35 // this class should behave like a bool, so the constructor shouldn't be explicit BooleanTestableBooleanTestable36 constexpr BooleanTestable(bool value) : value_{value} {} 37 constexpr BooleanTestable(const BooleanTestable&) = delete; 38 constexpr BooleanTestable(BooleanTestable&&) = delete; 39 40 private: 41 bool value_; 42 }; 43 44 static constexpr BooleanTestable yes(true); 45 static constexpr BooleanTestable no(false); 46 47 template <class T> 48 struct StrictComparable { 49 StrictComparable() = default; 50 51 // this shouldn't be explicit to make it easier to initialize inside arrays (which it almost always is) StrictComparableStrictComparable52 constexpr StrictComparable(T value) : value_{value} {} 53 54 friend constexpr BooleanTestable const& operator==(StrictComparable const& a, StrictComparable const& b) { 55 return a.value_ == b.value_ ? yes : no; 56 } 57 58 friend constexpr BooleanTestable const& operator!=(StrictComparable const& a, StrictComparable const& b) { 59 return a.value_ != b.value_ ? yes : no; 60 } 61 62 friend constexpr BooleanTestable const& operator<(StrictComparable const& a, StrictComparable const& b) { 63 return a.value_ < b.value_ ? yes : no; 64 } 65 friend constexpr BooleanTestable const& operator<=(StrictComparable const& a, StrictComparable const& b) { 66 return a.value_ <= b.value_ ? yes : no; 67 } 68 friend constexpr BooleanTestable const& operator>(StrictComparable const& a, StrictComparable const& b) { 69 return a.value_ > b.value_ ? yes : no; 70 } 71 friend constexpr BooleanTestable const& operator>=(StrictComparable const& a, StrictComparable const& b) { 72 return a.value_ >= b.value_ ? yes : no; 73 } 74 75 T value_; 76 }; 77 78 auto StrictUnaryPredicate = []<class T>(StrictComparable<T> const& x) -> BooleanTestable const& { 79 return x.value_ < 0 ? yes : no; 80 }; 81 82 auto StrictBinaryPredicate = 83 []<class T>(StrictComparable<T> const& x, StrictComparable<T> const& y) -> BooleanTestable const& { 84 return x.value_ < y.value_ ? yes : no; 85 }; 86 87 template <class It> 88 struct StrictBooleanIterator { 89 using value_type = typename std::iterator_traits<It>::value_type; 90 using reference = typename std::iterator_traits<It>::reference; 91 using difference_type = typename std::iterator_traits<It>::difference_type; 92 constexpr StrictBooleanIterator() = default; StrictBooleanIteratorStrictBooleanIterator93 constexpr explicit StrictBooleanIterator(It it) : iter_(it) {} 94 constexpr reference operator*() const { return *iter_; } 95 constexpr reference operator[](difference_type n) const { return iter_[n]; } 96 constexpr StrictBooleanIterator& operator++() { 97 ++iter_; 98 return *this; 99 } 100 constexpr StrictBooleanIterator operator++(int) { 101 auto copy = *this; 102 ++iter_; 103 return copy; 104 } 105 constexpr StrictBooleanIterator& operator--() { 106 --iter_; 107 return *this; 108 } 109 constexpr StrictBooleanIterator operator--(int) { 110 auto copy = *this; 111 --iter_; 112 return copy; 113 } 114 constexpr StrictBooleanIterator& operator+=(difference_type n) { 115 iter_ += n; 116 return *this; 117 } 118 constexpr StrictBooleanIterator& operator-=(difference_type n) { 119 iter_ -= n; 120 return *this; 121 } 122 friend constexpr StrictBooleanIterator operator+(StrictBooleanIterator x, difference_type n) { 123 x += n; 124 return x; 125 } 126 friend constexpr StrictBooleanIterator operator+(difference_type n, StrictBooleanIterator x) { 127 x += n; 128 return x; 129 } 130 friend constexpr StrictBooleanIterator operator-(StrictBooleanIterator x, difference_type n) { 131 x -= n; 132 return x; 133 } 134 friend constexpr difference_type operator-(StrictBooleanIterator x, StrictBooleanIterator y) { 135 return x.iter_ - y.iter_; 136 } 137 constexpr BooleanTestable const& operator==(StrictBooleanIterator const& other) const { 138 return iter_ == other.iter_ ? yes : no; 139 } 140 constexpr BooleanTestable const& operator!=(StrictBooleanIterator const& other) const { 141 return iter_ != other.iter_ ? yes : no; 142 } 143 constexpr BooleanTestable const& operator<(StrictBooleanIterator const& other) const { 144 return iter_ < other.iter_ ? yes : no; 145 } 146 constexpr BooleanTestable const& operator<=(StrictBooleanIterator const& other) const { 147 return iter_ <= other.iter_ ? yes : no; 148 } 149 constexpr BooleanTestable const& operator>(StrictBooleanIterator const& other) const { 150 return iter_ > other.iter_ ? yes : no; 151 } 152 constexpr BooleanTestable const& operator>=(StrictBooleanIterator const& other) const { 153 return iter_ >= other.iter_ ? yes : no; 154 } 155 156 private: 157 It iter_; 158 }; 159 static_assert(std::forward_iterator<StrictBooleanIterator<int*>>); 160 static_assert(std::sentinel_for<StrictBooleanIterator<int*>, StrictBooleanIterator<int*>>); 161 162 #endif // TEST_STD_VER > 17 163 164 #endif // LIBCXX_TEST_SUPPORT_BOOLEAN_TESTABLE_H 165