#include "base/containers/checked_iterators.h"
#include <algorithm>
#include <iterator>
#include "base/check_op.h"
#include "base/debug/alias.h"
#include "base/test/gtest_util.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
TEST(CheckedContiguousIterator, SatisfiesContiguousIteratorConcept) {
static_assert(std::contiguous_iterator<CheckedContiguousIterator<int>>);
}
template <class T, size_t N>
constexpr CheckedContiguousConstIterator<T> MakeConstIter(T (&arr)[N],
size_t cur) {
CHECK_LE(cur, N);
return
UNSAFE_BUFFERS(
CheckedContiguousConstIterator<T>(arr, arr + cur, arr + N));
}
template <class T, size_t N>
constexpr CheckedContiguousIterator<T> MakeIter(T (&arr)[N], size_t cur) {
CHECK_LE(cur, N);
return
UNSAFE_BUFFERS(CheckedContiguousIterator<T>(arr, arr + cur, arr + N));
}
TEST(CheckedContiguousIterator, StaticComparisonOperators) {
static constexpr int arr[] = {0};
constexpr CheckedContiguousConstIterator<int> begin = MakeConstIter(arr, 0u);
constexpr CheckedContiguousConstIterator<int> end = MakeConstIter(arr, 1u);
static_assert(begin == begin);
static_assert(end == end);
static_assert(begin != end);
static_assert(end != begin);
static_assert(begin < end);
static_assert(begin <= begin);
static_assert(begin <= end);
static_assert(end <= end);
static_assert(end > begin);
static_assert(end >= end);
static_assert(end >= begin);
static_assert(begin >= begin);
}
TEST(CheckedContiguousIterator, ConvertingComparisonOperators) {
static int arr[] = {0};
CheckedContiguousIterator<int> begin = MakeIter(arr, 0u);
CheckedContiguousConstIterator<int> cbegin = MakeConstIter(arr, 0u);
CheckedContiguousIterator<int> end = MakeIter(arr, 1u);
CheckedContiguousConstIterator<int> cend = MakeConstIter(arr, 1u);
EXPECT_EQ(begin, cbegin);
EXPECT_EQ(cbegin, begin);
EXPECT_EQ(end, cend);
EXPECT_EQ(cend, end);
EXPECT_NE(begin, cend);
EXPECT_NE(cbegin, end);
EXPECT_NE(end, cbegin);
EXPECT_NE(cend, begin);
EXPECT_LT(begin, cend);
EXPECT_LT(cbegin, end);
EXPECT_LE(begin, cbegin);
EXPECT_LE(cbegin, begin);
EXPECT_LE(begin, cend);
EXPECT_LE(cbegin, end);
EXPECT_LE(end, cend);
EXPECT_LE(cend, end);
EXPECT_GT(end, cbegin);
EXPECT_GT(cend, begin);
EXPECT_GE(end, cend);
EXPECT_GE(cend, end);
EXPECT_GE(end, cbegin);
EXPECT_GE(cend, begin);
EXPECT_GE(begin, cbegin);
EXPECT_GE(cbegin, begin);
}
TEST(CheckedContiguousIteratorDeathTest, OutOfBounds) {
static int arr[] = {0, 1, 2};
CheckedContiguousIterator<int> it = MakeIter(arr, 1u);
EXPECT_CHECK_DEATH(base::debug::Alias(&it[-2]));
EXPECT_EQ(it[-1], 0);
EXPECT_EQ(it[0], 1);
EXPECT_EQ(it[1], 2);
EXPECT_CHECK_DEATH(base::debug::Alias(&it[3]));
it += 2;
it -= 3;
it += 1;
EXPECT_CHECK_DEATH({
it -= 2;
base::debug::Alias(&it);
});
EXPECT_CHECK_DEATH({
it += 3;
base::debug::Alias(&it);
});
EXPECT_CHECK_DEATH({
auto o = it - 2;
base::debug::Alias(&o);
});
EXPECT_CHECK_DEATH({
auto o = it + 3;
base::debug::Alias(&o);
});
it++;
++it;
EXPECT_CHECK_DEATH({
++it;
base::debug::Alias(&it);
});
EXPECT_CHECK_DEATH({
it++;
base::debug::Alias(&it);
});
it -= 3;
EXPECT_CHECK_DEATH({
--it;
base::debug::Alias(&it);
});
EXPECT_CHECK_DEATH({
it--;
base::debug::Alias(&it);
});
}
}
namespace {
template <typename Iterator>
struct DisableDerefAndIncr : Iterator {
using Iterator::Iterator;
constexpr DisableDerefAndIncr(const Iterator& iter) : Iterator(iter) {}
void operator*() = delete;
void operator++() = delete;
void operator++(int) = delete;
};
}
template <typename Iter>
struct std::pointer_traits<DisableDerefAndIncr<Iter>>
: ::std::pointer_traits<Iter> {};
namespace base {
#if defined(_LIBCPP_VERSION)
TEST(CheckedContiguousIterator, OptimizedCopy) {
using Iter = DisableDerefAndIncr<CheckedContiguousIterator<int>>;
int arr_in[5] = {1, 2, 3, 4, 5};
int arr_out[5];
Iter in_begin = MakeIter(arr_in, 0u);
Iter in_end = MakeIter(arr_in, 5u);
Iter out_begin = MakeIter(arr_out, 0u);
Iter out_end = std::copy(in_begin, in_end, out_begin);
EXPECT_EQ(out_end, out_begin + (in_end - in_begin));
EXPECT_TRUE(std::ranges::equal(arr_in, arr_out));
}
#endif
}