1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <algorithm>
18 #include <vector>
19 
20 #include "gtest/gtest.h"
21 #include "transform_array_ref.h"
22 
23 namespace art {
24 
25 namespace {  // anonymous namespace
26 
27 struct ValueHolder {
28   // Deliberately not explicit.
ValueHolderart::__anon69bb46f00111::ValueHolder29   ValueHolder(int v) : value(v) { }  // NOLINT
30   int value;
31 };
32 
operator ==(const ValueHolder & lhs,const ValueHolder & rhs)33 ATTRIBUTE_UNUSED bool operator==(const ValueHolder& lhs, const ValueHolder& rhs) {
34   return lhs.value == rhs.value;
35 }
36 
37 }  // anonymous namespace
38 
TEST(TransformArrayRef,ConstRefAdd1)39 TEST(TransformArrayRef, ConstRefAdd1) {
40   auto add1 = [](const ValueHolder& h) { return h.value + 1; };
41   std::vector<ValueHolder> input({ 7, 6, 4, 0 });
42   std::vector<int> output;
43 
44   auto taref = MakeTransformArrayRef(input, add1);
45   using TarefIter = decltype(taref)::iterator;
46   using ConstTarefIter = decltype(taref)::const_iterator;
47   static_assert(std::is_same<int, decltype(taref)::value_type>::value, "value_type");
48   static_assert(std::is_same<TarefIter, decltype(taref)::pointer>::value, "pointer");
49   static_assert(std::is_same<int, decltype(taref)::reference>::value, "reference");
50   static_assert(std::is_same<ConstTarefIter, decltype(taref)::const_pointer>::value,
51                 "const_pointer");
52   static_assert(std::is_same<int, decltype(taref)::const_reference>::value, "const_reference");
53 
54   std::copy(taref.begin(), taref.end(), std::back_inserter(output));
55   ASSERT_EQ(std::vector<int>({ 8, 7, 5, 1 }), output);
56   output.clear();
57 
58   std::copy(taref.cbegin(), taref.cend(), std::back_inserter(output));
59   ASSERT_EQ(std::vector<int>({ 8, 7, 5, 1 }), output);
60   output.clear();
61 
62   std::copy(taref.rbegin(), taref.rend(), std::back_inserter(output));
63   ASSERT_EQ(std::vector<int>({ 1, 5, 7, 8 }), output);
64   output.clear();
65 
66   std::copy(taref.crbegin(), taref.crend(), std::back_inserter(output));
67   ASSERT_EQ(std::vector<int>({ 1, 5, 7, 8 }), output);
68   output.clear();
69 
70   ASSERT_EQ(input.size(), taref.size());
71   ASSERT_EQ(input.empty(), taref.empty());
72   ASSERT_EQ(input.front().value + 1, taref.front());
73   ASSERT_EQ(input.back().value + 1, taref.back());
74 
75   for (size_t i = 0; i != input.size(); ++i) {
76     ASSERT_EQ(input[i].value + 1, taref[i]);
77   }
78 }
79 
TEST(TransformArrayRef,NonConstRefSub1)80 TEST(TransformArrayRef, NonConstRefSub1) {
81   auto sub1 = [](ValueHolder& h) { return h.value - 1; };
82   std::vector<ValueHolder> input({ 4, 4, 5, 7, 10 });
83   std::vector<int> output;
84 
85   auto taref = MakeTransformArrayRef(input, sub1);
86   using TarefIter = decltype(taref)::iterator;
87   static_assert(std::is_same<void, decltype(taref)::const_iterator>::value, "const_iterator");
88   static_assert(std::is_same<int, decltype(taref)::value_type>::value, "value_type");
89   static_assert(std::is_same<TarefIter, decltype(taref)::pointer>::value, "pointer");
90   static_assert(std::is_same<int, decltype(taref)::reference>::value, "reference");
91   static_assert(std::is_same<void, decltype(taref)::const_pointer>::value, "const_pointer");
92   static_assert(std::is_same<void, decltype(taref)::const_reference>::value, "const_reference");
93 
94   std::copy(taref.begin(), taref.end(), std::back_inserter(output));
95   ASSERT_EQ(std::vector<int>({ 3, 3, 4, 6, 9 }), output);
96   output.clear();
97 
98   std::copy(taref.rbegin(), taref.rend(), std::back_inserter(output));
99   ASSERT_EQ(std::vector<int>({ 9, 6, 4, 3, 3 }), output);
100   output.clear();
101 
102   ASSERT_EQ(input.size(), taref.size());
103   ASSERT_EQ(input.empty(), taref.empty());
104   ASSERT_EQ(input.front().value - 1, taref.front());
105   ASSERT_EQ(input.back().value - 1, taref.back());
106 
107   for (size_t i = 0; i != input.size(); ++i) {
108     ASSERT_EQ(input[i].value - 1, taref[i]);
109   }
110 }
111 
TEST(TransformArrayRef,ConstAndNonConstRef)112 TEST(TransformArrayRef, ConstAndNonConstRef) {
113   struct Ref {
114     int& operator()(ValueHolder& h) const { return h.value; }
115     const int& operator()(const ValueHolder& h) const { return h.value; }
116   };
117   Ref ref;
118   std::vector<ValueHolder> input({ 1, 0, 1, 0, 3, 1 });
119   std::vector<int> output;
120 
121   auto taref = MakeTransformArrayRef(input, ref);
122   static_assert(std::is_same<int, decltype(taref)::value_type>::value, "value_type");
123   static_assert(std::is_same<int*, decltype(taref)::pointer>::value, "pointer");
124   static_assert(std::is_same<int&, decltype(taref)::reference>::value, "reference");
125   static_assert(std::is_same<const int*, decltype(taref)::const_pointer>::value, "const_pointer");
126   static_assert(std::is_same<const int&, decltype(taref)::const_reference>::value,
127                 "const_reference");
128 
129   std::copy(taref.begin(), taref.end(), std::back_inserter(output));
130   ASSERT_EQ(std::vector<int>({ 1, 0, 1, 0, 3, 1 }), output);
131   output.clear();
132 
133   std::copy(taref.cbegin(), taref.cend(), std::back_inserter(output));
134   ASSERT_EQ(std::vector<int>({ 1, 0, 1, 0, 3, 1 }), output);
135   output.clear();
136 
137   std::copy(taref.rbegin(), taref.rend(), std::back_inserter(output));
138   ASSERT_EQ(std::vector<int>({ 1, 3, 0, 1, 0, 1 }), output);
139   output.clear();
140 
141   std::copy(taref.crbegin(), taref.crend(), std::back_inserter(output));
142   ASSERT_EQ(std::vector<int>({ 1, 3, 0, 1, 0, 1 }), output);
143   output.clear();
144 
145   ASSERT_EQ(input.size(), taref.size());
146   ASSERT_EQ(input.empty(), taref.empty());
147   ASSERT_EQ(input.front().value, taref.front());
148   ASSERT_EQ(input.back().value, taref.back());
149 
150   for (size_t i = 0; i != input.size(); ++i) {
151     ASSERT_EQ(input[i].value, taref[i]);
152   }
153 
154   // Test writing through the transform iterator.
155   std::vector<int> transform_input({ 24, 37, 11, 71 });
156   std::vector<ValueHolder> transformed(transform_input.size(), 0);
157   taref = MakeTransformArrayRef(transformed, ref);
158   for (size_t i = 0; i != transform_input.size(); ++i) {
159     taref[i] = transform_input[i];
160   }
161   ASSERT_EQ(std::vector<ValueHolder>({ 24, 37, 11, 71 }), transformed);
162 
163   const std::vector<ValueHolder>& cinput = input;
164 
165   auto ctaref = MakeTransformArrayRef(cinput, ref);
166   static_assert(std::is_same<int, decltype(ctaref)::value_type>::value, "value_type");
167   static_assert(std::is_same<const int*, decltype(ctaref)::pointer>::value, "pointer");
168   static_assert(std::is_same<const int&, decltype(ctaref)::reference>::value, "reference");
169   static_assert(std::is_same<const int*, decltype(ctaref)::const_pointer>::value, "const_pointer");
170   static_assert(std::is_same<const int&, decltype(ctaref)::const_reference>::value,
171                 "const_reference");
172 
173   std::copy(ctaref.begin(), ctaref.end(), std::back_inserter(output));
174   ASSERT_EQ(std::vector<int>({ 1, 0, 1, 0, 3, 1 }), output);
175   output.clear();
176 
177   std::copy(std::begin(ctaref), std::end(ctaref), std::back_inserter(output));
178   ASSERT_EQ(std::vector<int>({ 1, 0, 1, 0, 3, 1 }), output);
179   output.clear();
180 
181   std::copy(ctaref.cbegin(), ctaref.cend(), std::back_inserter(output));
182   ASSERT_EQ(std::vector<int>({ 1, 0, 1, 0, 3, 1 }), output);
183   output.clear();
184 
185   std::copy(std::cbegin(ctaref), std::cend(ctaref), std::back_inserter(output));
186   ASSERT_EQ(std::vector<int>({ 1, 0, 1, 0, 3, 1 }), output);
187   output.clear();
188 
189   std::copy(ctaref.rbegin(), ctaref.rend(), std::back_inserter(output));
190   ASSERT_EQ(std::vector<int>({ 1, 3, 0, 1, 0, 1 }), output);
191   output.clear();
192 
193   std::copy(std::rbegin(ctaref), std::rend(ctaref), std::back_inserter(output));
194   ASSERT_EQ(std::vector<int>({ 1, 3, 0, 1, 0, 1 }), output);
195   output.clear();
196 
197   std::copy(ctaref.crbegin(), ctaref.crend(), std::back_inserter(output));
198   ASSERT_EQ(std::vector<int>({ 1, 3, 0, 1, 0, 1 }), output);
199   output.clear();
200 
201   std::copy(std::crbegin(ctaref), std::crend(ctaref), std::back_inserter(output));
202   ASSERT_EQ(std::vector<int>({ 1, 3, 0, 1, 0, 1 }), output);
203   output.clear();
204 
205   ASSERT_EQ(cinput.size(), ctaref.size());
206   ASSERT_EQ(cinput.empty(), ctaref.empty());
207   ASSERT_EQ(cinput.front().value, ctaref.front());
208   ASSERT_EQ(cinput.back().value, ctaref.back());
209 
210   for (size_t i = 0; i != cinput.size(); ++i) {
211     ASSERT_EQ(cinput[i].value, ctaref[i]);
212   }
213 
214   // Test conversion adding const.
215   decltype(ctaref) ctaref2 = taref;
216   ASSERT_EQ(taref.size(), ctaref2.size());
217   for (size_t i = 0; i != taref.size(); ++i) {
218     ASSERT_EQ(taref[i], ctaref2[i]);
219   }
220 }
221 
222 }  // namespace art
223