//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LIBCXX_TEST_SUPPORT_BOOLEAN_TESTABLE_H
#define LIBCXX_TEST_SUPPORT_BOOLEAN_TESTABLE_H
#include "test_macros.h"
#include <iterator>
#include <utility>
#if TEST_STD_VER > 17
struct BooleanTestable {
constexpr operator bool() const { return value_; }
friend constexpr BooleanTestable operator==(const BooleanTestable& lhs, const BooleanTestable& rhs) {
return lhs.value_ == rhs.value_;
}
friend constexpr BooleanTestable operator!=(const BooleanTestable& lhs, const BooleanTestable& rhs) {
return lhs.value_ != rhs.value_;
}
constexpr BooleanTestable&& operator!() && {
value_ = !value_;
return std::move(*this);
}
// this class should behave like a bool, so the constructor shouldn't be explicit
constexpr BooleanTestable(bool value) : value_{value} {}
constexpr BooleanTestable(const BooleanTestable&) = delete;
constexpr BooleanTestable(BooleanTestable&&) = delete;
private:
bool value_;
};
static constexpr BooleanTestable yes(true);
static constexpr BooleanTestable no(false);
template <class T>
struct StrictComparable {
StrictComparable() = default;
// this shouldn't be explicit to make it easier to initialize inside arrays (which it almost always is)
constexpr StrictComparable(T value) : value_{value} {}
friend constexpr BooleanTestable const& operator==(StrictComparable const& a, StrictComparable const& b) {
return a.value_ == b.value_ ? yes : no;
}
friend constexpr BooleanTestable const& operator!=(StrictComparable const& a, StrictComparable const& b) {
return a.value_ != b.value_ ? yes : no;
}
friend constexpr BooleanTestable const& operator<(StrictComparable const& a, StrictComparable const& b) {
return a.value_ < b.value_ ? yes : no;
}
friend constexpr BooleanTestable const& operator<=(StrictComparable const& a, StrictComparable const& b) {
return a.value_ <= b.value_ ? yes : no;
}
friend constexpr BooleanTestable const& operator>(StrictComparable const& a, StrictComparable const& b) {
return a.value_ > b.value_ ? yes : no;
}
friend constexpr BooleanTestable const& operator>=(StrictComparable const& a, StrictComparable const& b) {
return a.value_ >= b.value_ ? yes : no;
}
T value_;
};
auto StrictUnaryPredicate = []<class T>(StrictComparable<T> const& x) -> BooleanTestable const& {
return x.value_ < 0 ? yes : no;
};
auto StrictBinaryPredicate =
[]<class T>(StrictComparable<T> const& x, StrictComparable<T> const& y) -> BooleanTestable const& {
return x.value_ < y.value_ ? yes : no;
};
template <class It>
struct StrictBooleanIterator {
using value_type = typename std::iterator_traits<It>::value_type;
using reference = typename std::iterator_traits<It>::reference;
using difference_type = typename std::iterator_traits<It>::difference_type;
constexpr StrictBooleanIterator() = default;
constexpr explicit StrictBooleanIterator(It it) : iter_(it) {}
constexpr reference operator*() const { return *iter_; }
constexpr reference operator[](difference_type n) const { return iter_[n]; }
constexpr StrictBooleanIterator& operator++() {
++iter_;
return *this;
}
constexpr StrictBooleanIterator operator++(int) {
auto copy = *this;
++iter_;
return copy;
}
constexpr StrictBooleanIterator& operator--() {
--iter_;
return *this;
}
constexpr StrictBooleanIterator operator--(int) {
auto copy = *this;
--iter_;
return copy;
}
constexpr StrictBooleanIterator& operator+=(difference_type n) {
iter_ += n;
return *this;
}
constexpr StrictBooleanIterator& operator-=(difference_type n) {
iter_ -= n;
return *this;
}
friend constexpr StrictBooleanIterator operator+(StrictBooleanIterator x, difference_type n) {
x += n;
return x;
}
friend constexpr StrictBooleanIterator operator+(difference_type n, StrictBooleanIterator x) {
x += n;
return x;
}
friend constexpr StrictBooleanIterator operator-(StrictBooleanIterator x, difference_type n) {
x -= n;
return x;
}
friend constexpr difference_type operator-(StrictBooleanIterator x, StrictBooleanIterator y) {
return x.iter_ - y.iter_;
}
constexpr BooleanTestable const& operator==(StrictBooleanIterator const& other) const {
return iter_ == other.iter_ ? yes : no;
}
constexpr BooleanTestable const& operator!=(StrictBooleanIterator const& other) const {
return iter_ != other.iter_ ? yes : no;
}
constexpr BooleanTestable const& operator<(StrictBooleanIterator const& other) const {
return iter_ < other.iter_ ? yes : no;
}
constexpr BooleanTestable const& operator<=(StrictBooleanIterator const& other) const {
return iter_ <= other.iter_ ? yes : no;
}
constexpr BooleanTestable const& operator>(StrictBooleanIterator const& other) const {
return iter_ > other.iter_ ? yes : no;
}
constexpr BooleanTestable const& operator>=(StrictBooleanIterator const& other) const {
return iter_ >= other.iter_ ? yes : no;
}
private:
It iter_;
};
static_assert(std::forward_iterator<StrictBooleanIterator<int*>>);
static_assert(std::sentinel_for<StrictBooleanIterator<int*>, StrictBooleanIterator<int*>>);
#endif // TEST_STD_VER > 17
#endif // LIBCXX_TEST_SUPPORT_BOOLEAN_TESTABLE_H