• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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