1 | /* |
2 | * Copyright 2012-present 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_optional_path_simple) { |
74 | using std::map; |
75 | map<int, map<int, map<int, map<int, int>>>> m{{1, {{2, {{3, {{4, 5}}}}}}}}; |
76 | EXPECT_EQ(folly::Optional<int>(5), get_optional(m, 1, 2, 3, 4)); |
77 | EXPECT_TRUE(get_optional(m, 1, 2, 3, 4)); |
78 | EXPECT_FALSE(get_optional(m, 1, 2, 3, 0)); |
79 | EXPECT_TRUE(get_optional(m, 1, 2, 3)); |
80 | EXPECT_FALSE(get_optional(m, 1, 2, 0)); |
81 | EXPECT_TRUE(get_optional(m, 1, 2)); |
82 | EXPECT_FALSE(get_optional(m, 1, 0)); |
83 | EXPECT_TRUE(get_optional(m, 1)); |
84 | EXPECT_FALSE(get_optional(m, 0)); |
85 | } |
86 | |
87 | TEST(MapUtil, get_optional_path_mixed) { |
88 | using std::map; |
89 | using std::string; |
90 | using std::unordered_map; |
91 | unordered_map<string, map<int, map<string, int>>> m{{"a" , {{1, {{"b" , 2}}}}}}; |
92 | EXPECT_EQ(folly::Optional<int>(2), get_optional(m, "a" , 1, "b" )); |
93 | EXPECT_TRUE(get_optional(m, "a" , 1, "b" )); |
94 | EXPECT_FALSE(get_optional(m, "b" , 1, "b" )); |
95 | EXPECT_FALSE(get_optional(m, "a" , 2, "b" )); |
96 | EXPECT_FALSE(get_optional(m, "a" , 1, "c" )); |
97 | EXPECT_TRUE(get_optional(m, "a" , 1)); |
98 | EXPECT_TRUE(get_optional(m, "a" )); |
99 | } |
100 | |
101 | TEST(MapUtil, get_ref_default) { |
102 | std::map<int, int> m; |
103 | m[1] = 2; |
104 | const int i = 42; |
105 | EXPECT_EQ(2, get_ref_default(m, 1, i)); |
106 | EXPECT_EQ(42, get_ref_default(m, 2, i)); |
107 | EXPECT_EQ(std::addressof(i), std::addressof(get_ref_default(m, 2, i))); |
108 | } |
109 | |
110 | TEST(MapUtil, get_ref_default_function) { |
111 | std::map<int, int> m; |
112 | m[1] = 2; |
113 | const int i = 42; |
114 | EXPECT_EQ(2, get_ref_default(m, 1, [&i]() -> const int& { return i; })); |
115 | EXPECT_EQ(42, get_ref_default(m, 2, [&i]() -> const int& { return i; })); |
116 | EXPECT_EQ( |
117 | std::addressof(i), |
118 | std::addressof( |
119 | get_ref_default(m, 2, [&i]() -> const int& { return i; }))); |
120 | // statically disallowed: |
121 | // get_ref_default(m, 2, [] { return 7; }); |
122 | } |
123 | |
124 | TEST(MapUtil, get_ptr) { |
125 | std::map<int, int> m; |
126 | m[1] = 2; |
127 | EXPECT_EQ(2, *get_ptr(m, 1)); |
128 | EXPECT_TRUE(get_ptr(m, 2) == nullptr); |
129 | *get_ptr(m, 1) = 4; |
130 | EXPECT_EQ(4, m.at(1)); |
131 | } |
132 | |
133 | TEST(MapUtil, get_ptr_path_simple) { |
134 | using std::map; |
135 | map<int, map<int, map<int, map<int, int>>>> m{{1, {{2, {{3, {{4, 5}}}}}}}}; |
136 | EXPECT_EQ(5, *get_ptr(m, 1, 2, 3, 4)); |
137 | EXPECT_TRUE(get_ptr(m, 1, 2, 3, 4)); |
138 | EXPECT_FALSE(get_ptr(m, 1, 2, 3, 0)); |
139 | EXPECT_TRUE(get_ptr(m, 1, 2, 3)); |
140 | EXPECT_FALSE(get_ptr(m, 1, 2, 0)); |
141 | EXPECT_TRUE(get_ptr(m, 1, 2)); |
142 | EXPECT_FALSE(get_ptr(m, 1, 0)); |
143 | EXPECT_TRUE(get_ptr(m, 1)); |
144 | EXPECT_FALSE(get_ptr(m, 0)); |
145 | const auto& cm = m; |
146 | ++*get_ptr(m, 1, 2, 3, 4); |
147 | EXPECT_EQ(6, *get_ptr(cm, 1, 2, 3, 4)); |
148 | EXPECT_TRUE(get_ptr(cm, 1, 2, 3, 4)); |
149 | EXPECT_FALSE(get_ptr(cm, 1, 2, 3, 0)); |
150 | } |
151 | |
152 | TEST(MapUtil, get_ptr_path_mixed) { |
153 | using std::map; |
154 | using std::string; |
155 | using std::unordered_map; |
156 | unordered_map<string, map<int, map<string, int>>> m{{"a" , {{1, {{"b" , 7}}}}}}; |
157 | EXPECT_EQ(7, *get_ptr(m, "a" , 1, "b" )); |
158 | EXPECT_TRUE(get_ptr(m, "a" , 1, "b" )); |
159 | EXPECT_FALSE(get_ptr(m, "b" , 1, "b" )); |
160 | EXPECT_FALSE(get_ptr(m, "a" , 2, "b" )); |
161 | EXPECT_FALSE(get_ptr(m, "a" , 1, "c" )); |
162 | EXPECT_TRUE(get_ptr(m, "a" , 1)); |
163 | EXPECT_TRUE(get_ptr(m, "a" )); |
164 | const auto& cm = m; |
165 | ++*get_ptr(m, "a" , 1, "b" ); |
166 | EXPECT_EQ(8, *get_ptr(cm, "a" , 1, "b" )); |
167 | EXPECT_TRUE(get_ptr(cm, "a" , 1, "b" )); |
168 | EXPECT_FALSE(get_ptr(cm, "b" , 1, "b" )); |
169 | } |
170 | |
171 | namespace { |
172 | template <typename T> |
173 | struct element_type { |
174 | using type = typename std::decay<T>::type; |
175 | }; |
176 | |
177 | template <typename T> |
178 | struct element_type<T()> { |
179 | using type = T; |
180 | }; |
181 | |
182 | template <typename T> |
183 | using element_type_t = typename element_type<T>::type; |
184 | |
185 | template <typename T, typename = void> |
186 | struct Compiles : std::false_type {}; |
187 | |
188 | template <typename T> |
189 | struct Compiles< |
190 | T, |
191 | void_t<decltype(get_ref_default( |
192 | std::declval<std::map<int, element_type_t<T>>>(), |
193 | std::declval<int>(), |
194 | std::declval<T>()))>> : std::true_type {}; |
195 | } // namespace |
196 | |
197 | TEST(MapUtil, get_default_temporary) { |
198 | EXPECT_TRUE(Compiles<const int&>::value); |
199 | EXPECT_TRUE(Compiles<int&>::value); |
200 | EXPECT_FALSE(Compiles<const int&&>::value); |
201 | EXPECT_FALSE(Compiles<int&&>::value); |
202 | |
203 | EXPECT_TRUE(Compiles<const int&()>::value); |
204 | EXPECT_TRUE(Compiles<int&()>::value); |
205 | EXPECT_FALSE(Compiles<int()>::value); |
206 | } |
207 | |
208 | TEST(MapUtil, get_default_path) { |
209 | using std::map; |
210 | map<int, map<int, int>> m; |
211 | m[4][2] = 42; |
212 | EXPECT_EQ(42, get_default(m, 4, 2, 42)); |
213 | EXPECT_EQ(42, get_default(m, 1, 3, 42)); |
214 | } |
215 | |
216 | TEST(MapUtil, get_default_path_mixed) { |
217 | using std::map; |
218 | using std::string; |
219 | using std::unordered_map; |
220 | map<int, unordered_map<string, StringPiece>> m; |
221 | int key1 = 42; |
222 | const string key2 = "hello" ; |
223 | constexpr StringPiece value = "world" ; |
224 | constexpr StringPiece dflt = "default" ; |
225 | m[key1][key2] = value; |
226 | EXPECT_EQ(value, get_default(m, 42, key2, dflt)); |
227 | EXPECT_EQ(value, get_default(m, key1, "hello" , dflt)); |
228 | EXPECT_EQ(dflt, get_default(m, 0, key2, dflt)); |
229 | EXPECT_EQ(dflt, get_default(m, key1, "bad" , "default" )); |
230 | } |
231 | |
232 | TEST(MapUtil, get_ref_default_path) { |
233 | using std::map; |
234 | map<int, map<int, int>> m; |
235 | m[4][2] = 42; |
236 | const int dflt = 13; |
237 | EXPECT_EQ(42, get_ref_default(m, 4, 2, dflt)); |
238 | EXPECT_EQ(dflt, get_ref_default(m, 1, 3, dflt)); |
239 | } |
240 | |
241 | TEST(MapUtil, get_ref_default_path_mixed) { |
242 | using std::map; |
243 | using std::string; |
244 | using std::unordered_map; |
245 | map<int, unordered_map<string, StringPiece>> m; |
246 | int key1 = 42; |
247 | const string key2 = "hello" ; |
248 | constexpr StringPiece value = "world" ; |
249 | constexpr StringPiece dflt = "default" ; |
250 | m[key1][key2] = value; |
251 | EXPECT_EQ(value, get_ref_default(m, 42, key2, dflt)); |
252 | EXPECT_EQ(value, get_ref_default(m, key1, "hello" , dflt)); |
253 | EXPECT_EQ(dflt, get_ref_default(m, 0, key2, dflt)); |
254 | EXPECT_EQ(dflt, get_ref_default(m, key1, "bad" , dflt)); |
255 | } |
256 | |
257 | namespace { |
258 | template <typename T, typename = void> |
259 | struct GetRefDefaultPathCompiles : std::false_type {}; |
260 | |
261 | template <typename T> |
262 | struct GetRefDefaultPathCompiles< |
263 | T, |
264 | void_t<decltype(get_ref_default( |
265 | std::declval<std::map<int, std::map<int, element_type_t<T>>>>(), |
266 | std::declval<int>(), |
267 | std::declval<int>(), |
268 | std::declval<T>()))>> : std::true_type {}; |
269 | } // namespace |
270 | |
271 | TEST(MapUtil, get_ref_default_path_temporary) { |
272 | EXPECT_TRUE(GetRefDefaultPathCompiles<const int&>::value); |
273 | EXPECT_TRUE(GetRefDefaultPathCompiles<int&>::value); |
274 | EXPECT_FALSE(GetRefDefaultPathCompiles<const int&&>::value); |
275 | EXPECT_FALSE(GetRefDefaultPathCompiles<int&&>::value); |
276 | } |
277 | |
278 | namespace { |
279 | |
280 | class TestConstruction { |
281 | public: |
282 | TestConstruction() { |
283 | EXPECT_TRUE(false); |
284 | } |
285 | TestConstruction(TestConstruction&&) { |
286 | EXPECT_TRUE(false); |
287 | } |
288 | TestConstruction(const TestConstruction&) { |
289 | EXPECT_TRUE(false); |
290 | } |
291 | |
292 | explicit TestConstruction(std::string&& string) |
293 | : string_{std::move(string)} {} |
294 | explicit TestConstruction(int&& integer) : integer_{integer} {} |
295 | |
296 | TestConstruction& operator=(const TestConstruction&) = delete; |
297 | TestConstruction& operator=(TestConstruction&&) = delete; |
298 | |
299 | int integer_{}; |
300 | std::string string_{}; |
301 | }; |
302 | |
303 | } // namespace |
304 | |
305 | TEST(MapUtil, test_get_default_deferred_construction) { |
306 | auto map = std::unordered_map<int, TestConstruction>{}; |
307 | map.emplace( |
308 | std::piecewise_construct, |
309 | std::forward_as_tuple(1), |
310 | std::forward_as_tuple(1)); |
311 | |
312 | EXPECT_EQ(map.at(1).integer_, 1); |
313 | |
314 | { |
315 | auto val = get_default(map, 0, 1); |
316 | EXPECT_EQ(val.integer_, 1); |
317 | EXPECT_EQ(val.string_, "" ); |
318 | } |
319 | |
320 | { |
321 | auto val = get_default(map, 0, "something" ); |
322 | EXPECT_EQ(val.integer_, 0); |
323 | EXPECT_EQ(val.string_, "something" ); |
324 | } |
325 | } |
326 | |