Split get_default() into two for deferred default construction
[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
243 } // namespace
244
245 TEST(MapUtil, get_ref_default_path_temporary) {
246   EXPECT_TRUE(GetRefDefaultPathCompiles<const int&>::value);
247   EXPECT_TRUE(GetRefDefaultPathCompiles<int&>::value);
248   EXPECT_FALSE(GetRefDefaultPathCompiles<const int&&>::value);
249   EXPECT_FALSE(GetRefDefaultPathCompiles<int&&>::value);
250 }
251
252 namespace {
253
254 class TestConstruction {
255  public:
256   static std::size_t numberDefaultConstructs;
257   TestConstruction() {
258     ++numberDefaultConstructs;
259   }
260   TestConstruction(TestConstruction&&) = default;
261   TestConstruction(const TestConstruction&) = default;
262
263   TestConstruction& operator=(const TestConstruction&) = delete;
264   TestConstruction& operator=(TestConstruction&&) = delete;
265 };
266
267 std::size_t TestConstruction::numberDefaultConstructs = 0;
268
269 } // namespace
270
271 TEST(MapUtil, test_get_default_deferred_construction) {
272   auto map = std::unordered_map<int, TestConstruction>{};
273   map.insert({1, TestConstruction{}});
274
275   EXPECT_EQ(TestConstruction::numberDefaultConstructs, 1);
276
277   {
278     auto val = get_default(map, 1);
279     EXPECT_EQ(TestConstruction::numberDefaultConstructs, 1);
280     static_cast<void>(val);
281   }
282
283   {
284     auto val = get_default(map, 1, TestConstruction{});
285     EXPECT_EQ(TestConstruction::numberDefaultConstructs, 2);
286     static_cast<void>(val);
287   }
288 }