54f64efedeeed9996d39fdb3245d1b0734a8167a
[folly.git] / folly / test / FBVectorTest.cpp
1 /*
2  * Copyright 2016 Facebook, Inc.
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 //
18 // Author: andrei.alexandrescu@fb.com
19
20 #include <folly/Foreach.h>
21 #include <folly/Traits.h>
22 #include <folly/Random.h>
23 #include <folly/FBString.h>
24 #include <folly/FBVector.h>
25 #include <folly/portability/GTest.h>
26
27 #include <list>
28 #include <map>
29 #include <memory>
30 #include <boost/random.hpp>
31
32 using namespace std;
33 using namespace folly;
34
35 namespace {
36
37 auto static const seed = randomNumberSeed();
38 typedef boost::mt19937 RandomT;
39 static RandomT rng(seed);
40
41 template <class Integral1, class Integral2>
42 Integral2 random(Integral1 low, Integral2 up) {
43   boost::uniform_int<> range(low, up);
44   return range(rng);
45 }
46
47 template <class String>
48 void randomString(String* toFill, unsigned int maxSize = 1000) {
49   assert(toFill);
50   toFill->resize(random(0, maxSize));
51   FOR_EACH (i, *toFill) {
52     *i = random('a', 'z');
53   }
54 }
55
56 template <class String, class Integral>
57 void Num2String(String& str, Integral /* n */) {
58   str.resize(10, '\0');
59   sprintf(&str[0], "%ul", 10);
60   str.resize(strlen(str.c_str()));
61 }
62
63 template<class T> T randomObject();
64
65 template<> int randomObject<int>() {
66   return random(0, 1024);
67 }
68 }
69
70 ////////////////////////////////////////////////////////////////////////////////
71 // Tests begin here
72 ////////////////////////////////////////////////////////////////////////////////
73
74 TEST(fbvector, clause_23_3_6_1_3_ambiguity) {
75   fbvector<int> v(10, 20);
76   EXPECT_EQ(v.size(), 10);
77   FOR_EACH (i, v) {
78     EXPECT_EQ(*i, 20);
79   }
80 }
81
82 TEST(fbvector, clause_23_3_6_1_11_ambiguity) {
83   fbvector<int> v;
84   v.assign(10, 20);
85   EXPECT_EQ(v.size(), 10);
86   FOR_EACH (i, v) {
87     EXPECT_EQ(*i, 20);
88   }
89 }
90
91 TEST(fbvector, clause_23_3_6_2_6) {
92   fbvector<int> v;
93   auto const n = random(0U, 10000U);
94   v.reserve(n);
95   auto const n1 = random(0U, 10000U);
96   auto const obj = randomObject<int>();
97   v.assign(n1, obj);
98   v.shrink_to_fit();
99   // Nothing to verify except that the call made it through
100 }
101
102 TEST(fbvector, clause_23_3_6_4_ambiguity) {
103   fbvector<int> v;
104   fbvector<int>::const_iterator i = v.end();
105   v.insert(i, 10, 20);
106   EXPECT_EQ(v.size(), 10);
107   FOR_EACH (i, v) {
108     EXPECT_EQ(*i, 20);
109   }
110 }
111
112 TEST(fbvector, composition) {
113   fbvector< fbvector<double> > matrix(100, fbvector<double>(100));
114 }
115
116 TEST(fbvector, works_with_std_string) {
117   fbvector<std::string> v(10, "hello");
118   EXPECT_EQ(v.size(), 10);
119   v.push_back("world");
120 }
121
122 namespace {
123 class UserDefinedType { int whatevs_; };
124 }
125
126 FOLLY_ASSUME_FBVECTOR_COMPATIBLE(UserDefinedType);
127
128 TEST(fbvector, works_with_user_defined_type) {
129   fbvector<UserDefinedType> v(10);
130   EXPECT_EQ(v.size(), 10);
131   v.push_back(UserDefinedType());
132 }
133
134 TEST(fbvector, move_construction) {
135   fbvector<int> v1(100, 100);
136   fbvector<int> v2;
137   EXPECT_EQ(v1.size(), 100);
138   EXPECT_EQ(v1.front(), 100);
139   EXPECT_EQ(v2.size(), 0);
140   v2 = std::move(v1);
141   EXPECT_EQ(v1.size(), 0);
142   EXPECT_EQ(v2.size(), 100);
143   EXPECT_EQ(v2.front(), 100);
144
145   v1.assign(100, 100);
146   auto other = std::move(v1);
147   EXPECT_EQ(v1.size(), 0);
148   EXPECT_EQ(other.size(), 100);
149   EXPECT_EQ(other.front(), 100);
150 }
151
152 TEST(fbvector, emplace) {
153   fbvector<std::string> s(12, "asd");
154   EXPECT_EQ(s.size(), 12);
155   EXPECT_EQ(s.front(), "asd");
156   s.emplace_back("funk");
157   EXPECT_EQ(s.back(), "funk");
158 }
159
160 TEST(fbvector, initializer_lists) {
161   fbvector<int> vec = { 1, 2, 3 };
162   EXPECT_EQ(vec.size(), 3);
163   EXPECT_EQ(vec[0], 1);
164   EXPECT_EQ(vec[1], 2);
165   EXPECT_EQ(vec[2], 3);
166
167   vec = { 0, 0, 12, 16 };
168   EXPECT_EQ(vec.size(), 4);
169   EXPECT_EQ(vec[0], 0);
170   EXPECT_EQ(vec[1], 0);
171   EXPECT_EQ(vec[2], 12);
172   EXPECT_EQ(vec[3], 16);
173
174   vec.insert(vec.begin() + 1, { 23, 23 });
175   EXPECT_EQ(vec.size(), 6);
176   EXPECT_EQ(vec[0], 0);
177   EXPECT_EQ(vec[1], 23);
178   EXPECT_EQ(vec[2], 23);
179   EXPECT_EQ(vec[3], 0);
180   EXPECT_EQ(vec[4], 12);
181   EXPECT_EQ(vec[5], 16);
182 }
183
184 TEST(fbvector, unique_ptr) {
185   fbvector<std::unique_ptr<int> > v(12);
186   std::unique_ptr<int> p(new int(12));
187   v.push_back(std::move(p));
188   EXPECT_EQ(*v.back(), 12);
189
190   v[0] = std::move(p);
191   EXPECT_FALSE(v[0].get());
192   v[0].reset(new int(32));
193   std::unique_ptr<int> somePtr;
194   v.insert(v.begin(), std::move(somePtr));
195   EXPECT_EQ(*v[1], 32);
196 }
197
198 TEST(FBVector, task858056) {
199   fbvector<fbstring> cycle;
200   cycle.push_back("foo");
201   cycle.push_back("bar");
202   cycle.push_back("baz");
203   fbstring message("Cycle detected: ");
204   FOR_EACH_R (node_name, cycle) {
205     message += "[";
206     message += *node_name;
207     message += "] ";
208   }
209   EXPECT_EQ("Cycle detected: [baz] [bar] [foo] ", message);
210 }
211
212 TEST(FBVector, move_iterator) {
213   fbvector<int> base = { 0, 1, 2 };
214
215   auto cp1 = base;
216   fbvector<int> fbvi1(std::make_move_iterator(cp1.begin()),
217                       std::make_move_iterator(cp1.end()));
218   EXPECT_EQ(fbvi1, base);
219
220   auto cp2 = base;
221   fbvector<int> fbvi2;
222   fbvi2.assign(std::make_move_iterator(cp2.begin()),
223                std::make_move_iterator(cp2.end()));
224   EXPECT_EQ(fbvi2, base);
225
226   auto cp3 = base;
227   fbvector<int> fbvi3;
228   fbvi3.insert(fbvi3.end(),
229                std::make_move_iterator(cp3.begin()),
230                std::make_move_iterator(cp3.end()));
231   EXPECT_EQ(fbvi3, base);
232 }
233
234 TEST(FBVector, reserve_consistency) {
235   struct S { int64_t a, b, c, d; };
236
237   fbvector<S> fb1;
238   for (size_t i = 0; i < 1000; ++i) {
239     fb1.reserve(1);
240     EXPECT_EQ(fb1.size(), 0);
241     fb1.shrink_to_fit();
242   }
243 }
244
245 TEST(FBVector, vector_of_maps) {
246   fbvector<std::map<std::string, std::string>> v;
247
248   v.push_back(std::map<std::string, std::string>());
249   v.push_back(std::map<std::string, std::string>());
250
251   EXPECT_EQ(2, v.size());
252
253   v[1]["hello"] = "world";
254   EXPECT_EQ(0, v[0].size());
255   EXPECT_EQ(1, v[1].size());
256
257   v[0]["foo"] = "bar";
258   EXPECT_EQ(1, v[0].size());
259   EXPECT_EQ(1, v[1].size());
260 }
261
262 TEST(FBVector, shrink_to_fit_after_clear) {
263   fbvector<int> fb1;
264   fb1.push_back(42);
265   fb1.push_back(1337);
266   fb1.clear();
267   fb1.shrink_to_fit();
268   EXPECT_EQ(fb1.size(), 0);
269   EXPECT_EQ(fb1.capacity(), 0);
270 }