1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/containers/adapters.h"
6
7 #include <ranges>
8 #include <utility>
9 #include <vector>
10
11 #include "base/containers/span.h"
12 #include "base/containers/to_vector.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 namespace {
16
17 class UnsizedVector {
18 public:
19 UnsizedVector() = default;
UnsizedVector(std::initializer_list<int> il)20 UnsizedVector(std::initializer_list<int> il) : v_(il) {}
21
22 // Sentinel iterator type that wraps `end()` to ensure this type doesn't
23 // satisfy the `sized_range` concept.
24 template <typename Iterator>
25 class Sentinel {
26 public:
27 Sentinel() = default;
Sentinel(Iterator it)28 explicit Sentinel(Iterator it) : wrapped_it_(it) {}
29
operator ==(Iterator it) const30 bool operator==(Iterator it) const { return wrapped_it_ == it; }
31
32 private:
33 Iterator wrapped_it_;
34 };
35
begin() const36 auto begin() const { return v_.begin(); }
end() const37 auto end() const { return Sentinel(v_.end()); }
rbegin() const38 auto rbegin() const { return v_.rbegin(); }
rend() const39 auto rend() const { return Sentinel(v_.rend()); }
begin()40 auto begin() { return v_.begin(); }
end()41 auto end() { return Sentinel(v_.end()); }
rbegin()42 auto rbegin() { return v_.rbegin(); }
rend()43 auto rend() { return Sentinel(v_.rend()); }
44
operator [](size_t pos) const45 auto operator[](size_t pos) const { return v_[pos]; }
operator [](size_t pos)46 auto operator[](size_t pos) { return v_[pos]; }
47
48 private:
49 std::vector<int> v_;
50 };
51
StaticAsserts()52 [[maybe_unused]] void StaticAsserts() {
53 {
54 // Named local variables are more readable than std::declval<T>().
55 std::vector<int> v;
56 static_assert(std::ranges::range<decltype(base::Reversed(v))>);
57 static_assert(std::ranges::sized_range<decltype(base::Reversed(v))>);
58 // `base::Reversed()` takes a const ref to the vector, which is, by
59 // definition, a borrowed range.
60 static_assert(std::ranges::borrowed_range<decltype(base::Reversed(v))>);
61
62 auto make_vector = [] { return std::vector<int>(); };
63 static_assert(std::ranges::range<decltype(base::Reversed(make_vector()))>);
64 static_assert(
65 std::ranges::sized_range<decltype(base::Reversed(make_vector()))>);
66 static_assert(
67 !std::ranges::borrowed_range<decltype(base::Reversed(make_vector()))>);
68 }
69
70 {
71 base::span<int> s;
72 static_assert(std::ranges::range<decltype(base::Reversed(s))>);
73 static_assert(std::ranges::sized_range<decltype(base::Reversed(s))>);
74 static_assert(std::ranges::borrowed_range<decltype(base::Reversed(s))>);
75
76 auto rvalue_span = [] { return base::span<int>(); };
77 static_assert(std::ranges::range<decltype(base::Reversed(rvalue_span()))>);
78 static_assert(
79 std::ranges::sized_range<decltype(base::Reversed(rvalue_span()))>);
80 static_assert(
81 std::ranges::borrowed_range<decltype(base::Reversed(rvalue_span()))>);
82 }
83
84 {
85 // A named local variable is more readable than std::declval<T>().
86 UnsizedVector v;
87 static_assert(std::ranges::range<decltype(v)>);
88 static_assert(!std::ranges::sized_range<decltype(v)>);
89
90 static_assert(std::ranges::range<decltype(base::Reversed(v))>);
91 static_assert(!std::ranges::sized_range<decltype(base::Reversed(v))>);
92 // `base::Reversed()` takes a const ref to the vector, which is, by
93 // definition, a borrowed range.
94 static_assert(std::ranges::borrowed_range<decltype(base::Reversed(v))>);
95
96 auto make_vector = [] { return UnsizedVector(); };
97 static_assert(std::ranges::range<decltype(base::Reversed(make_vector()))>);
98 static_assert(
99 !std::ranges::sized_range<decltype(base::Reversed(make_vector()))>);
100 static_assert(!std::ranges::borrowed_range<decltype(make_vector())>);
101 }
102 }
103
TEST(AdaptersTest,Reversed)104 TEST(AdaptersTest, Reversed) {
105 std::vector<int> v = {3, 2, 1};
106 int j = 0;
107 for (int& i : base::Reversed(v)) {
108 EXPECT_EQ(++j, i);
109 i += 100;
110 }
111 EXPECT_EQ(103, v[0]);
112 EXPECT_EQ(102, v[1]);
113 EXPECT_EQ(101, v[2]);
114 }
115
TEST(AdaptersTest,ReversedUnsized)116 TEST(AdaptersTest, ReversedUnsized) {
117 UnsizedVector v = {3, 2, 1};
118 int j = 0;
119 for (int& i : base::Reversed(v)) {
120 EXPECT_EQ(++j, i);
121 i += 100;
122 }
123 EXPECT_EQ(103, v[0]);
124 EXPECT_EQ(102, v[1]);
125 EXPECT_EQ(101, v[2]);
126 }
127
TEST(AdaptersTest,ReversedArray)128 TEST(AdaptersTest, ReversedArray) {
129 int v[3] = {3, 2, 1};
130 int j = 0;
131 for (int& i : base::Reversed(v)) {
132 EXPECT_EQ(++j, i);
133 i += 100;
134 }
135 EXPECT_EQ(103, v[0]);
136 EXPECT_EQ(102, v[1]);
137 EXPECT_EQ(101, v[2]);
138 }
139
TEST(AdaptersTest,ReversedConst)140 TEST(AdaptersTest, ReversedConst) {
141 std::vector<int> v = {3, 2, 1};
142 const std::vector<int>& cv = v;
143 int j = 0;
144 for (int i : base::Reversed(cv)) {
145 EXPECT_EQ(++j, i);
146 }
147 }
148
TEST(AdaptersTest,RangeAsRvalues)149 TEST(AdaptersTest, RangeAsRvalues) {
150 std::vector<std::unique_ptr<int>> v;
151 v.push_back(std::make_unique<int>(1));
152 v.push_back(std::make_unique<int>(2));
153 v.push_back(std::make_unique<int>(3));
154
155 auto v2 = base::ToVector(base::RangeAsRvalues(std::move(v)));
156 EXPECT_EQ(1, *v2[0]);
157 EXPECT_EQ(2, *v2[1]);
158 EXPECT_EQ(3, *v2[2]);
159
160 // The old vector should be consumed. The standard guarantees that a
161 // moved-from std::unique_ptr will be null.
162 EXPECT_EQ(nullptr, v[0]); // NOLINT(bugprone-use-after-move)
163 EXPECT_EQ(nullptr, v[1]); // NOLINT(bugprone-use-after-move)
164 EXPECT_EQ(nullptr, v[2]); // NOLINT(bugprone-use-after-move)
165 }
166
167 } // namespace
168