blob: 279d887facdf5e64a85754543beabe83f929ae07 [file]
// Copyright 2025 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
#include "pw_containers/ptr_iterator.h"
#include <array>
#include <iterator>
#include <type_traits>
#include "pw_unit_test/framework.h"
namespace {
// Create a fake container for use with PtrIterator.
class FakeVector {
public:
using value_type = int;
using reference = int&;
using const_reference = const int&;
using pointer = int*;
using const_pointer = const int*;
using iterator = pw::containers::PtrIterator<FakeVector>;
using const_iterator = pw::containers::ConstPtrIterator<FakeVector>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
constexpr FakeVector(int* data, size_t length)
: data_(data), length_(length) {}
iterator begin() { return iterator(data_); }
iterator end() { return iterator(data_ + length_); }
const_iterator begin() const { return const_iterator(data_); }
const_iterator end() const { return const_iterator(data_ + length_); }
reverse_iterator rbegin() { return reverse_iterator(end()); }
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rbegin() const {
return const_reverse_iterator(end());
}
const_reverse_iterator rend() const {
return const_reverse_iterator(begin());
}
private:
int* data_;
size_t length_;
};
static_assert(std::is_same_v<std::iterator_traits<pw::containers::PtrIterator<
FakeVector>>::iterator_category,
pw::containers::contiguous_iterator_tag>);
static_assert(
std::is_same_v<std::iterator_traits<pw::containers::ConstPtrIterator<
FakeVector>>::iterator_category,
pw::containers::contiguous_iterator_tag>);
static_assert(!std::is_convertible_v<FakeVector::iterator, int*>);
static_assert(!std::is_convertible_v<int*, FakeVector::iterator>);
static_assert(
std::is_convertible_v<FakeVector::iterator, FakeVector::const_iterator>);
static_assert(
!std::is_convertible_v<FakeVector::const_iterator, FakeVector::iterator>);
TEST(PtrIterator, DefaultConstructor) {
pw::containers::PtrIterator<FakeVector> it;
pw::containers::ConstPtrIterator<FakeVector> cit;
EXPECT_EQ(it, pw::containers::PtrIterator<FakeVector>());
EXPECT_EQ(cit, pw::containers::ConstPtrIterator<FakeVector>());
}
TEST(PtrIterator, IterateForwards) {
std::array<int, 5> data{1, 2, 3, 4, 5};
FakeVector vec(data.data(), data.size());
int expected = 1;
for (int val : vec) {
EXPECT_EQ(val, expected++);
}
std::array<int, 3> data2{10, 20, 30};
FakeVector vec2(data2.data(), data2.size());
expected = 10;
for (int val : vec2) {
EXPECT_EQ(val, expected);
expected += 10;
}
}
TEST(PtrIterator, ReverseIterate) {
std::array<int, 5> data{1, 2, 3, 4, 5};
FakeVector vec(data.data(), data.size());
int expected = 5;
for (FakeVector::reverse_iterator it = vec.rbegin(); it != vec.rend(); ++it) {
EXPECT_EQ(*it, expected--);
}
const FakeVector& cvec = vec;
expected = 5;
for (FakeVector::const_reverse_iterator it = cvec.rbegin(); it != cvec.rend();
++it) {
EXPECT_EQ(*it, expected--);
}
}
TEST(PtrIterator, IterateBackwards) {
std::array<int, 5> data{1, 2, 3, 4, 5};
FakeVector vec(data.data(), data.size());
FakeVector::iterator it = vec.end();
int expected = 5;
do {
--it;
EXPECT_EQ(*it, expected--);
} while (it != vec.begin());
std::array<int, 2> data2{100, 200};
FakeVector vec2(data2.data(), data2.size());
FakeVector::iterator it2 = vec2.end();
int expected2 = 200;
do {
--it2;
EXPECT_EQ(*it2, expected2);
expected2 -= 100;
} while (it2 != vec2.begin());
}
TEST(PtrIterator, PostIncrement) {
std::array<int, 2> data{1, 2};
FakeVector vec(data.data(), data.size());
FakeVector::iterator it = vec.begin();
EXPECT_EQ(*(it++), 1);
EXPECT_EQ(*it, 2);
}
TEST(PtrIterator, PreIncrement) {
std::array<int, 3> data{1, 2, 3};
FakeVector vec(data.data(), data.size());
FakeVector::iterator it = vec.begin();
EXPECT_EQ(*(++it), 2);
EXPECT_EQ(*it, 2);
}
TEST(PtrIterator, PostDecrement) {
std::array<int, 4> data{1, 2, 3, 4};
FakeVector vec(data.data(), data.size());
FakeVector::iterator it = vec.end();
--it;
EXPECT_EQ(*(it--), 4);
EXPECT_EQ(*it, 3);
}
TEST(PtrIterator, PreDecrement) {
std::array<int, 5> data{1, 2, 3, 4, 5};
FakeVector vec(data.data(), data.size());
FakeVector::iterator it = vec.end();
--it;
EXPECT_EQ(*(--it), 4);
EXPECT_EQ(*it, 4);
}
TEST(PtrIterator, Addition) {
std::array<int, 6> data{1, 2, 3, 4, 5, 6};
FakeVector vec(data.data(), data.size());
FakeVector::iterator it = vec.begin();
EXPECT_EQ(*(it + 2), 3);
EXPECT_EQ(*(2 + it), 3);
it += 4;
EXPECT_EQ(*it, 5);
}
TEST(PtrIterator, Subtraction) {
std::array<int, 7> data{1, 2, 3, 4, 5, 6, 7};
FakeVector vec(data.data(), data.size());
FakeVector::iterator it = vec.end();
EXPECT_EQ(*(it - 2), 6);
it -= 3;
EXPECT_EQ(*it, 5);
}
TEST(PtrIterator, Difference) {
std::array<int, 8> data{1, 2, 3, 4, 5, 6, 7, 8};
FakeVector vec(data.data(), data.size());
EXPECT_EQ(vec.end() - vec.begin(), 8);
std::array<int, 1> data2{1};
FakeVector vec2(data2.data(), data2.size());
EXPECT_EQ(vec2.end() - vec2.begin(), 1);
}
TEST(PtrIterator, Comparison) {
std::array<int, 5> data{1, 2, 3, 4, 5};
FakeVector vec(data.data(), data.size());
FakeVector::iterator it1 = vec.begin();
FakeVector::iterator it2 = vec.begin();
EXPECT_TRUE(it1 == it2);
EXPECT_FALSE(it1 != it2);
EXPECT_FALSE(it1 < it2);
EXPECT_TRUE(it1 <= it2);
EXPECT_FALSE(it1 > it2);
EXPECT_TRUE(it1 >= it2);
++it2;
EXPECT_FALSE(it1 == it2);
EXPECT_TRUE(it1 != it2);
EXPECT_TRUE(it1 < it2);
EXPECT_TRUE(it1 <= it2);
EXPECT_FALSE(it1 > it2);
EXPECT_FALSE(it1 >= it2);
}
TEST(PtrIterator, ConstConversion) {
std::array<int, 5> data{1, 2, 3, 4, 5};
FakeVector vec(data.data(), data.size());
FakeVector::iterator it = vec.begin();
FakeVector::const_iterator cit = it;
EXPECT_EQ(*it, *cit);
}
TEST(PtrIterator, ArrayAccess) {
std::array<int, 4> data{1, 2, 3, 4};
FakeVector vec(data.data(), data.size());
FakeVector::iterator it = vec.begin();
EXPECT_EQ(it[2], 3);
EXPECT_EQ(it[0], 1);
EXPECT_EQ(it[3], 4);
}
} // namespace