7ef13f718fcf757e50fc2e7a202bcbb118cabc01
[folly.git] / folly / test / MapUtilTest.cpp
1 /*
2  * Copyright 2017 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 #include <folly/MapUtil.h>
18
19 #include <cstddef>
20 #include <map>
21 #include <unordered_map>
22
23 #include <folly/Traits.h>
24 #include <folly/portability/GTest.h>
25
26 using namespace folly;
27
28 TEST(MapUtil, get_default) {
29   std::map<int, int> m;
30   m[1] = 2;
31   EXPECT_EQ(2, get_default(m, 1, 42));
32   EXPECT_EQ(42, get_default(m, 2, 42));
33   EXPECT_EQ(0, get_default(m, 3));
34 }
35
36 TEST(MapUtil, get_default_function) {
37   std::map<int, int> m;
38   m[1] = 2;
39   EXPECT_EQ(2, get_default(m, 1, [] { return 42; }));
40   EXPECT_EQ(42, get_default(m, 2, [] { return 42; }));
41   EXPECT_EQ(0, get_default(m, 3));
42 }
43
44 TEST(MapUtil, get_or_throw) {
45   std::map<int, int> m;
46   m[1] = 2;
47   EXPECT_EQ(2, get_or_throw(m, 1));
48   EXPECT_THROW(get_or_throw(m, 2), std::out_of_range);
49   EXPECT_EQ(&m[1], &get_or_throw(m, 1));
50   get_or_throw(m, 1) = 3;
51   EXPECT_EQ(3, get_or_throw(m, 1));
52   const auto& cm = m;
53   EXPECT_EQ(&m[1], &get_or_throw(cm, 1));
54   EXPECT_EQ(3, get_or_throw(cm, 1));
55   EXPECT_THROW(get_or_throw(cm, 2), std::out_of_range);
56 }
57
58 TEST(MapUtil, get_or_throw_specified) {
59   std::map<int, int> m;
60   m[1] = 2;
61   EXPECT_EQ(2, get_or_throw<std::runtime_error>(m, 1));
62   EXPECT_THROW(get_or_throw<std::runtime_error>(m, 2), std::runtime_error);
63 }
64
65 TEST(MapUtil, get_optional) {
66   std::map<int, int> m;
67   m[1] = 2;
68   EXPECT_TRUE(get_optional(m, 1).hasValue());
69   EXPECT_EQ(2, get_optional(m, 1).value());
70   EXPECT_FALSE(get_optional(m, 2).hasValue());
71 }
72
73 TEST(MapUtil, get_ref_default) {
74   std::map<int, int> m;
75   m[1] = 2;
76   const int i = 42;
77   EXPECT_EQ(2, get_ref_default(m, 1, i));
78   EXPECT_EQ(42, get_ref_default(m, 2, i));
79   EXPECT_EQ(std::addressof(i), std::addressof(get_ref_default(m, 2, i)));
80 }
81
82 TEST(MapUtil, get_ref_default_function) {
83   std::map<int, int> m;
84   m[1] = 2;
85   const int i = 42;
86   EXPECT_EQ(2, get_ref_default(m, 1, [&i]() -> const int& { return i; }));
87   EXPECT_EQ(42, get_ref_default(m, 2, [&i]() -> const int& { return i; }));
88   EXPECT_EQ(
89       std::addressof(i),
90       std::addressof(
91           get_ref_default(m, 2, [&i]() -> const int& { return i; })));
92   // statically disallowed:
93   // get_ref_default(m, 2, [] { return 7; });
94 }
95
96 TEST(MapUtil, get_ptr) {
97   std::map<int, int> m;
98   m[1] = 2;
99   EXPECT_EQ(2, *get_ptr(m, 1));
100   EXPECT_TRUE(get_ptr(m, 2) == nullptr);
101   *get_ptr(m, 1) = 4;
102   EXPECT_EQ(4, m.at(1));
103 }
104
105 TEST(MapUtil, get_ptr_path_simple) {
106   using std::map;
107   map<int, map<int, map<int, map<int, int>>>> m{{1, {{2, {{3, {{4, 5}}}}}}}};
108   EXPECT_EQ(5, *get_ptr(m, 1, 2, 3, 4));
109   EXPECT_TRUE(get_ptr(m, 1, 2, 3, 4));
110   EXPECT_FALSE(get_ptr(m, 1, 2, 3, 0));
111   EXPECT_TRUE(get_ptr(m, 1, 2, 3));
112   EXPECT_FALSE(get_ptr(m, 1, 2, 0));
113   EXPECT_TRUE(get_ptr(m, 1, 2));
114   EXPECT_FALSE(get_ptr(m, 1, 0));
115   EXPECT_TRUE(get_ptr(m, 1));
116   EXPECT_FALSE(get_ptr(m, 0));
117   const auto& cm = m;
118   ++*get_ptr(m, 1, 2, 3, 4);
119   EXPECT_EQ(6, *get_ptr(cm, 1, 2, 3, 4));
120   EXPECT_TRUE(get_ptr(cm, 1, 2, 3, 4));
121   EXPECT_FALSE(get_ptr(cm, 1, 2, 3, 0));
122 }
123
124 TEST(MapUtil, get_ptr_path_mixed) {
125   using std::map;
126   using std::unordered_map;
127   using std::string;
128   unordered_map<string, map<int, map<string, int>>> m{{"a", {{1, {{"b", 7}}}}}};
129   EXPECT_EQ(7, *get_ptr(m, "a", 1, "b"));
130   EXPECT_TRUE(get_ptr(m, "a", 1, "b"));
131   EXPECT_FALSE(get_ptr(m, "b", 1, "b"));
132   EXPECT_FALSE(get_ptr(m, "a", 2, "b"));
133   EXPECT_FALSE(get_ptr(m, "a", 1, "c"));
134   EXPECT_TRUE(get_ptr(m, "a", 1, "b"));
135   EXPECT_TRUE(get_ptr(m, "a", 1));
136   EXPECT_TRUE(get_ptr(m, "a"));
137   const auto& cm = m;
138   ++*get_ptr(m, "a", 1, "b");
139   EXPECT_EQ(8, *get_ptr(cm, "a", 1, "b"));
140   EXPECT_TRUE(get_ptr(cm, "a", 1, "b"));
141   EXPECT_FALSE(get_ptr(cm, "b", 1, "b"));
142 }
143
144 namespace {
145 template <typename T>
146 struct element_type {
147   using type = typename std::decay<T>::type;
148 };
149
150 template <typename T>
151 struct element_type<T()> {
152   using type = T;
153 };
154
155 template <typename T>
156 using element_type_t = typename element_type<T>::type;
157
158 template <typename T, typename = void>
159 struct Compiles : std::false_type {};
160
161 template <typename T>
162 struct Compiles<
163     T,
164     void_t<decltype(get_ref_default(
165         std::declval<std::map<int, element_type_t<T>>>(),
166         std::declval<int>(),
167         std::declval<T>()))>> : std::true_type {};
168 } // namespace
169
170 TEST(MapUtil, get_default_temporary) {
171   EXPECT_TRUE(Compiles<const int&>::value);
172   EXPECT_TRUE(Compiles<int&>::value);
173   EXPECT_FALSE(Compiles<const int&&>::value);
174   EXPECT_FALSE(Compiles<int&&>::value);
175
176   EXPECT_TRUE(Compiles<const int&()>::value);
177   EXPECT_TRUE(Compiles<int&()>::value);
178   EXPECT_FALSE(Compiles<int()>::value);
179 }
180
181 TEST(MapUtil, get_default_path) {
182   using std::map;
183   map<int, map<int, int>> m;
184   m[4][2] = 42;
185   EXPECT_EQ(42, get_default(m, 4, 2, 42));
186   EXPECT_EQ(42, get_default(m, 1, 3, 42));
187 }
188
189 TEST(MapUtil, get_default_path_mixed) {
190   using std::map;
191   using std::unordered_map;
192   using std::string;
193   map<int, unordered_map<string, StringPiece>> m;
194   int key1 = 42;
195   const string key2 = "hello";
196   constexpr StringPiece value = "world";
197   constexpr StringPiece dflt = "default";
198   m[key1][key2] = value;
199   EXPECT_EQ(value, get_default(m, 42, key2, dflt));
200   EXPECT_EQ(value, get_default(m, key1, "hello", dflt));
201   EXPECT_EQ(dflt, get_default(m, 0, key2, dflt));
202   EXPECT_EQ(dflt, get_default(m, key1, "bad", "default"));
203 }
204
205 TEST(MapUtil, get_ref_default_path) {
206   using std::map;
207   map<int, map<int, int>> m;
208   m[4][2] = 42;
209   const int dflt = 13;
210   EXPECT_EQ(42, get_ref_default(m, 4, 2, dflt));
211   EXPECT_EQ(dflt, get_ref_default(m, 1, 3, dflt));
212 }
213
214 TEST(MapUtil, get_ref_default_path_mixed) {
215   using std::map;
216   using std::unordered_map;
217   using std::string;
218   map<int, unordered_map<string, StringPiece>> m;
219   int key1 = 42;
220   const string key2 = "hello";
221   constexpr StringPiece value = "world";
222   constexpr StringPiece dflt = "default";
223   m[key1][key2] = value;
224   EXPECT_EQ(value, get_ref_default(m, 42, key2, dflt));
225   EXPECT_EQ(value, get_ref_default(m, key1, "hello", dflt));
226   EXPECT_EQ(dflt, get_ref_default(m, 0, key2, dflt));
227   EXPECT_EQ(dflt, get_ref_default(m, key1, "bad", dflt));
228 }
229
230 namespace {
231 template <typename T, typename = void>
232 struct GetRefDefaultPathCompiles : std::false_type {};
233
234 template <typename T>
235 struct GetRefDefaultPathCompiles<
236     T,
237     void_t<decltype(get_ref_default(
238         std::declval<std::map<int, std::map<int, element_type_t<T>>>>(),
239         std::declval<int>(),
240         std::declval<int>(),
241         std::declval<T>()))>> : std::true_type {};
242 } // namespace
243
244 TEST(MapUtil, get_ref_default_path_temporary) {
245   EXPECT_TRUE(GetRefDefaultPathCompiles<const int&>::value);
246   EXPECT_TRUE(GetRefDefaultPathCompiles<int&>::value);
247   EXPECT_FALSE(GetRefDefaultPathCompiles<const int&&>::value);
248   EXPECT_FALSE(GetRefDefaultPathCompiles<int&&>::value);
249 }
250
251 namespace {
252
253 class TestConstruction {
254  public:
255   TestConstruction() {
256     EXPECT_TRUE(false);
257   }
258   TestConstruction(TestConstruction&&) {
259     EXPECT_TRUE(false);
260   }
261   TestConstruction(const TestConstruction&) {
262     EXPECT_TRUE(false);
263   }
264
265   explicit TestConstruction(std::string&& string)
266       : string_{std::move(string)} {}
267   explicit TestConstruction(int&& integer) : integer_{integer} {}
268
269   TestConstruction& operator=(const TestConstruction&) = delete;
270   TestConstruction& operator=(TestConstruction&&) = delete;
271
272   int integer_{};
273   std::string string_{};
274 };
275
276 } // namespace
277
278 TEST(MapUtil, test_get_default_deferred_construction) {
279   auto map = std::unordered_map<int, TestConstruction>{};
280   map.emplace(
281       std::piecewise_construct,
282       std::forward_as_tuple(1),
283       std::forward_as_tuple(1));
284
285   EXPECT_EQ(map.at(1).integer_, 1);
286
287   {
288     auto val = get_default(map, 0, 1);
289     EXPECT_EQ(val.integer_, 1);
290     EXPECT_EQ(val.string_, "");
291   }
292
293   {
294     auto val = get_default(map, 0, "something");
295     EXPECT_EQ(val.integer_, 0);
296     EXPECT_EQ(val.string_, "something");
297   }
298 }