1 // Copyright 2021 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/extend.h"
6
7 #include <initializer_list>
8 #include <type_traits>
9 #include <utility>
10 #include <vector>
11
12 #include "base/containers/adapters.h"
13 #include "base/containers/circular_deque.h"
14 #include "base/containers/span.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 namespace base {
19
20 namespace {
21
22 using testing::ElementsAre;
23
24 struct NonCopyable {
25 char c_;
NonCopyablebase::__anon373c01710111::NonCopyable26 explicit NonCopyable(char c) : c_(c) {}
27 NonCopyable(NonCopyable&&) = default;
28 NonCopyable& operator=(NonCopyable&& other) = default;
29
30 NonCopyable(const NonCopyable&) = delete;
31 NonCopyable& operator=(const NonCopyable&) = delete;
32 };
33
operator ==(const NonCopyable & a,const NonCopyable & b)34 bool operator==(const NonCopyable& a, const NonCopyable& b) {
35 return a.c_ == b.c_;
36 }
37
38 static_assert(std::is_move_constructible_v<NonCopyable>, "");
39 static_assert(!std::is_copy_constructible_v<NonCopyable>, "");
40
41 struct CopyableMovable {
42 bool copied_;
43 char c_;
CopyableMovablebase::__anon373c01710111::CopyableMovable44 explicit CopyableMovable(char c) : copied_(false), c_(c) {}
CopyableMovablebase::__anon373c01710111::CopyableMovable45 CopyableMovable(const CopyableMovable& other) : copied_(true), c_(other.c_) {}
46
47 CopyableMovable& operator=(const CopyableMovable&) = default;
48 CopyableMovable(CopyableMovable&&) = default;
49 CopyableMovable& operator=(CopyableMovable&& other) = default;
50 };
51
operator ==(const CopyableMovable & a,const CopyableMovable & b)52 bool operator==(const CopyableMovable& a, const CopyableMovable& b) {
53 return a.c_ == b.c_;
54 }
55
56 } // namespace
57
TEST(ExtendTest,ExtendWithMove)58 TEST(ExtendTest, ExtendWithMove) {
59 std::vector<NonCopyable> dst;
60 for (char c : {'a', 'b', 'c', 'd'})
61 dst.emplace_back(c);
62 std::vector<NonCopyable> src;
63 for (char c : {'e', 'f', 'g'})
64 src.emplace_back(c);
65 std::vector<NonCopyable> expected;
66 for (char c : {'a', 'b', 'c', 'd', 'e', 'f', 'g'})
67 expected.emplace_back(c);
68
69 Extend(dst, std::move(src));
70 EXPECT_EQ(dst, expected);
71 EXPECT_TRUE(src.empty());
72 }
73
TEST(ExtendTest,ExtendCopyableWithMove)74 TEST(ExtendTest, ExtendCopyableWithMove) {
75 std::vector<CopyableMovable> dst;
76 for (char c : {'a', 'b', 'c', 'd'})
77 dst.emplace_back(c);
78 std::vector<CopyableMovable> src;
79 for (char c : {'e', 'f', 'g'})
80 src.emplace_back(c);
81 std::vector<CopyableMovable> expected;
82 for (char c : {'a', 'b', 'c', 'd', 'e', 'f', 'g'})
83 expected.emplace_back(c);
84
85 Extend(dst, std::move(src));
86 EXPECT_EQ(dst, expected);
87 EXPECT_TRUE(src.empty());
88 }
89
TEST(ExtendTest,ExtendWithCopy)90 TEST(ExtendTest, ExtendWithCopy) {
91 std::vector<CopyableMovable> dst;
92 for (char c : {'a', 'b', 'c', 'd'})
93 dst.emplace_back(c);
94 std::vector<CopyableMovable> src;
95 for (char c : {'e', 'f', 'g'})
96 src.emplace_back(c);
97 std::vector<CopyableMovable> expected;
98 for (char c : {'a', 'b', 'c', 'd', 'e', 'f', 'g'})
99 expected.emplace_back(c);
100
101 EXPECT_FALSE(dst[0].copied_);
102 Extend(dst, src);
103 EXPECT_EQ(dst, expected);
104 EXPECT_FALSE(dst[0].copied_);
105 EXPECT_TRUE(dst[dst.size() - 1].copied_);
106 }
107
TEST(ExtendTest,ExtendWithSpan)108 TEST(ExtendTest, ExtendWithSpan) {
109 static constexpr uint8_t kRawArray[] = {3, 4, 5};
110
111 static constexpr auto kVectorGenerator = []() -> std::vector<uint8_t> {
112 return {9, 10, 11};
113 };
114
115 static const std::vector<uint8_t> kConstVector = kVectorGenerator();
116 static std::vector<uint8_t> kMutVector = kVectorGenerator();
117
118 std::vector<uint8_t> dst;
119
120 // Selects overload for span<const uint8_t, 3>.
121 Extend(dst, span(kRawArray));
122 EXPECT_THAT(dst, ElementsAre(3, 4, 5));
123
124 // Selects overload for span<uint8_t, 3>.
125 static std::array<uint8_t, 3> kArray = {6, 7, 8};
126 Extend(dst, span(kArray));
127 EXPECT_THAT(dst, ElementsAre(3, 4, 5, 6, 7, 8));
128
129 // Selects overload for span<const uint8_t, dynamic_extent>.
130 Extend(dst, span(kConstVector));
131 EXPECT_THAT(dst, ElementsAre(3, 4, 5, 6, 7, 8, 9, 10, 11));
132
133 // Selects overload for span<uint8_t, dynamic_extent>.
134 Extend(dst, span(kMutVector));
135 EXPECT_THAT(dst, ElementsAre(3, 4, 5, 6, 7, 8, 9, 10, 11, 9, 10, 11));
136
137 // Input is convertible to span.
138 Extend(dst, kRawArray);
139 EXPECT_THAT(dst,
140 ElementsAre(3, 4, 5, 6, 7, 8, 9, 10, 11, 9, 10, 11, 3, 4, 5));
141 }
142
TEST(ExtendTest,ExtendWithRanges)143 TEST(ExtendTest, ExtendWithRanges) {
144 std::set<int> set = {1, 2, 3};
145 circular_deque<int> deque = {4, 5, 6};
146 {
147 std::vector<int> dst;
148 Extend(dst, Reversed(set));
149 EXPECT_THAT(dst, ElementsAre(3, 2, 1));
150 Extend(dst, Reversed(deque));
151 EXPECT_THAT(dst, ElementsAre(3, 2, 1, 6, 5, 4));
152 }
153
154 {
155 std::vector<int> dst;
156 Extend(dst, set, [](int val) { return -val; });
157 EXPECT_THAT(dst, ElementsAre(-1, -2, -3));
158 Extend(dst, deque, [](int val) { return val + 1; });
159 EXPECT_THAT(dst, ElementsAre(-1, -2, -3, 5, 6, 7));
160 }
161
162 {
163 std::vector<int> dst;
164 Extend(dst, Reversed(set), [](int val) { return val * val; });
165 EXPECT_THAT(dst, ElementsAre(9, 4, 1));
166 Extend(dst, Reversed(deque), [](int val) { return val - 1; });
167 EXPECT_THAT(dst, ElementsAre(9, 4, 1, 5, 4, 3));
168 }
169 }
170
171 } // namespace base
172