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
26using namespace folly;
27
28TEST(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
36TEST(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
44TEST(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
58TEST(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
65TEST(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
73TEST(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
87TEST(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
101TEST(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
110TEST(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
124TEST(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
133TEST(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
152TEST(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
171namespace {
172template <typename T>
173struct element_type {
174 using type = typename std::decay<T>::type;
175};
176
177template <typename T>
178struct element_type<T()> {
179 using type = T;
180};
181
182template <typename T>
183using element_type_t = typename element_type<T>::type;
184
185template <typename T, typename = void>
186struct Compiles : std::false_type {};
187
188template <typename T>
189struct 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
197TEST(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
208TEST(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
216TEST(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
232TEST(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
241TEST(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
257namespace {
258template <typename T, typename = void>
259struct GetRefDefaultPathCompiles : std::false_type {};
260
261template <typename T>
262struct 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
271TEST(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
278namespace {
279
280class 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
305TEST(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