// Copyright 2014 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/containers/adapters.h" #include #include #include #include "base/containers/span.h" #include "base/containers/to_vector.h" #include "testing/gtest/include/gtest/gtest.h" namespace { class UnsizedVector { public: UnsizedVector() = default; UnsizedVector(std::initializer_list il) : v_(il) {} // Sentinel iterator type that wraps `end()` to ensure this type doesn't // satisfy the `sized_range` concept. template class Sentinel { public: Sentinel() = default; explicit Sentinel(Iterator it) : wrapped_it_(it) {} bool operator==(Iterator it) const { return wrapped_it_ == it; } private: Iterator wrapped_it_; }; auto begin() const { return v_.begin(); } auto end() const { return Sentinel(v_.end()); } auto rbegin() const { return v_.rbegin(); } auto rend() const { return Sentinel(v_.rend()); } auto begin() { return v_.begin(); } auto end() { return Sentinel(v_.end()); } auto rbegin() { return v_.rbegin(); } auto rend() { return Sentinel(v_.rend()); } auto operator[](size_t pos) const { return v_[pos]; } auto operator[](size_t pos) { return v_[pos]; } private: std::vector v_; }; [[maybe_unused]] void StaticAsserts() { { // Named local variables are more readable than std::declval(). std::vector v; static_assert(std::ranges::range); static_assert(std::ranges::sized_range); // `base::Reversed()` takes a const ref to the vector, which is, by // definition, a borrowed range. static_assert(std::ranges::borrowed_range); auto make_vector = [] { return std::vector(); }; static_assert(std::ranges::range); static_assert( std::ranges::sized_range); static_assert( !std::ranges::borrowed_range); } { base::span s; static_assert(std::ranges::range); static_assert(std::ranges::sized_range); static_assert(std::ranges::borrowed_range); auto rvalue_span = [] { return base::span(); }; static_assert(std::ranges::range); static_assert( std::ranges::sized_range); static_assert( std::ranges::borrowed_range); } { // A named local variable is more readable than std::declval(). UnsizedVector v; static_assert(std::ranges::range); static_assert(!std::ranges::sized_range); static_assert(std::ranges::range); static_assert(!std::ranges::sized_range); // `base::Reversed()` takes a const ref to the vector, which is, by // definition, a borrowed range. static_assert(std::ranges::borrowed_range); auto make_vector = [] { return UnsizedVector(); }; static_assert(std::ranges::range); static_assert( !std::ranges::sized_range); static_assert(!std::ranges::borrowed_range); } } TEST(AdaptersTest, Reversed) { std::vector v = {3, 2, 1}; int j = 0; for (int& i : base::Reversed(v)) { EXPECT_EQ(++j, i); i += 100; } EXPECT_EQ(103, v[0]); EXPECT_EQ(102, v[1]); EXPECT_EQ(101, v[2]); } TEST(AdaptersTest, ReversedUnsized) { UnsizedVector v = {3, 2, 1}; int j = 0; for (int& i : base::Reversed(v)) { EXPECT_EQ(++j, i); i += 100; } EXPECT_EQ(103, v[0]); EXPECT_EQ(102, v[1]); EXPECT_EQ(101, v[2]); } TEST(AdaptersTest, ReversedArray) { int v[3] = {3, 2, 1}; int j = 0; for (int& i : base::Reversed(v)) { EXPECT_EQ(++j, i); i += 100; } EXPECT_EQ(103, v[0]); EXPECT_EQ(102, v[1]); EXPECT_EQ(101, v[2]); } TEST(AdaptersTest, ReversedConst) { std::vector v = {3, 2, 1}; const std::vector& cv = v; int j = 0; for (int i : base::Reversed(cv)) { EXPECT_EQ(++j, i); } } TEST(AdaptersTest, RangeAsRvalues) { std::vector> v; v.push_back(std::make_unique(1)); v.push_back(std::make_unique(2)); v.push_back(std::make_unique(3)); auto v2 = base::ToVector(base::RangeAsRvalues(std::move(v))); EXPECT_EQ(1, *v2[0]); EXPECT_EQ(2, *v2[1]); EXPECT_EQ(3, *v2[2]); // The old vector should be consumed. The standard guarantees that a // moved-from std::unique_ptr will be null. EXPECT_EQ(nullptr, v[0]); // NOLINT(bugprone-use-after-move) EXPECT_EQ(nullptr, v[1]); // NOLINT(bugprone-use-after-move) EXPECT_EQ(nullptr, v[2]); // NOLINT(bugprone-use-after-move) } } // namespace