/root/doris/be/src/gutil/map-util.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2005 Google Inc. |
2 | | // |
3 | | // #status: RECOMMENDED |
4 | | // #category: maps |
5 | | // #summary: Utility functions for use with map-like containers. |
6 | | // |
7 | | // This file provides utility functions for use with STL map-like data |
8 | | // structures, such as std::map and hash_map. Some functions will also work with |
9 | | // sets, such as ContainsKey(). |
10 | | // |
11 | | // The main functions in this file fall into the following categories: |
12 | | // |
13 | | // - Find*() |
14 | | // - Contains*() |
15 | | // - Insert*() |
16 | | // - Lookup*() |
17 | | // |
18 | | // These functions often have "...OrDie" or "...OrDieNoPrint" variants. These |
19 | | // variants will crash the process with a CHECK() failure on error, including |
20 | | // the offending key/data in the log message. The NoPrint variants will not |
21 | | // include the key/data in the log output under the assumption that it's not a |
22 | | // printable type. |
23 | | // |
24 | | // Most functions are fairly self explanatory from their names, with the |
25 | | // exception of Find*() vs Lookup*(). The Find functions typically use the map's |
26 | | // .find() member function to locate and return the map's value type. The |
27 | | // Lookup*() functions typically use the map's .insert() (yes, insert) member |
28 | | // function to insert the given value if necessary and returns (usually a |
29 | | // reference to) the map's value type for the found item. |
30 | | // |
31 | | // See the per-function comments for specifics. |
32 | | // |
33 | | // There are also a handful of functions for doing other miscellaneous things. |
34 | | // |
35 | | // A note on terminology: |
36 | | // |
37 | | // Map-like containers are collections of pairs. Like all STL containers they |
38 | | // contain a few standard typedefs identifying the types of data they contain. |
39 | | // Given the following map declaration: |
40 | | // |
41 | | // map<string, int> my_map; |
42 | | // |
43 | | // the notable typedefs would be as follows: |
44 | | // |
45 | | // - key_type -- string |
46 | | // - value_type -- pair<const string, int> |
47 | | // - mapped_type -- int |
48 | | // |
49 | | // Note that the map above contains two types of "values": the key-value pairs |
50 | | // themselves (value_type) and the values within the key-value pairs |
51 | | // (mapped_type). A value_type consists of a key_type and a mapped_type. |
52 | | // |
53 | | // The documentation below is written for programmers thinking in terms of keys |
54 | | // and the (mapped_type) values associated with a given key. For example, the |
55 | | // statement |
56 | | // |
57 | | // my_map["foo"] = 3; |
58 | | // |
59 | | // has a key of "foo" (type: string) with a value of 3 (type: int). |
60 | | // |
61 | | |
62 | | #pragma once |
63 | | |
64 | | #include <glog/logging.h> |
65 | | #include <stddef.h> |
66 | | |
67 | | #include <tuple> |
68 | | #include <utility> |
69 | | #include <vector> |
70 | | |
71 | | #include "gutil/logging-inl.h" |
72 | | |
73 | | // |
74 | | // Find*() |
75 | | // |
76 | | |
77 | | // Returns a const reference to the value associated with the given key if it |
78 | | // exists. Crashes otherwise. |
79 | | // |
80 | | // This is intended as a replacement for operator[] as an rvalue (for reading) |
81 | | // when the key is guaranteed to exist. |
82 | | // |
83 | | // operator[] for lookup is discouraged for several reasons: |
84 | | // * It has a side-effect of inserting missing keys |
85 | | // * It is not thread-safe (even when it is not inserting, it can still |
86 | | // choose to resize the underlying storage) |
87 | | // * It invalidates iterators (when it chooses to resize) |
88 | | // * It default constructs a value object even if it doesn't need to |
89 | | // |
90 | | // This version assumes the key is printable, and includes it in the fatal log |
91 | | // message. |
92 | | template <class Collection> |
93 | | const typename Collection::mapped_type& FindOrDie(const Collection& collection, |
94 | | const typename Collection::key_type& key) { |
95 | | auto it = collection.find(key); |
96 | | CHECK(it != collection.end()) << "Map key not found: " << key; |
97 | | return it->second; |
98 | | } |
99 | | |
100 | | // Same as above, but returns a non-const reference. |
101 | | template <class Collection> |
102 | | typename Collection::mapped_type& FindOrDie(Collection& collection, // NOLINT |
103 | | const typename Collection::key_type& key) { |
104 | | auto it = collection.find(key); |
105 | | CHECK(it != collection.end()) << "Map key not found: " << key; |
106 | | return it->second; |
107 | | } |
108 | | |
109 | | // Same as FindOrDie above, but doesn't log the key on failure. |
110 | | template <class Collection> |
111 | | const typename Collection::mapped_type& FindOrDieNoPrint(const Collection& collection, |
112 | | const typename Collection::key_type& key) { |
113 | | typename Collection::const_iterator it = collection.find(key); |
114 | | CHECK(it != collection.end()) << "Map key not found"; |
115 | | return it->second; |
116 | | } |
117 | | |
118 | | // Same as above, but returns a non-const reference. |
119 | | template <class Collection> |
120 | | typename Collection::mapped_type& FindOrDieNoPrint(Collection& collection, // NOLINT |
121 | | const typename Collection::key_type& key) { |
122 | | typename Collection::iterator it = collection.find(key); |
123 | | CHECK(it != collection.end()) << "Map key not found"; |
124 | | return it->second; |
125 | | } |
126 | | |
127 | | // Returns a const reference to the value associated with the given key if it |
128 | | // exists, otherwise a const reference to the provided default value is |
129 | | // returned. |
130 | | // |
131 | | // WARNING: If a temporary object is passed as the default "value," this |
132 | | // function will return a reference to that temporary object, which will be |
133 | | // destroyed by the end of the statement. Specifically, if you have a map with |
134 | | // string values, and you pass a char* as the default "value," either use the |
135 | | // returned value immediately or store it in a string (not string&). Details: |
136 | | template <class Collection> |
137 | | const typename Collection::mapped_type& FindWithDefault( |
138 | | const Collection& collection, const typename Collection::key_type& key, |
139 | | const typename Collection::mapped_type& value) { |
140 | | auto it = collection.find(key); |
141 | | if (it == collection.end()) { |
142 | | return value; |
143 | | } |
144 | | return it->second; |
145 | | } |
146 | | |
147 | | // Returns a pointer to the const value associated with the given key if it |
148 | | // exists, or NULL otherwise. |
149 | | template <class Collection> |
150 | | const typename Collection::mapped_type* FindOrNull(const Collection& collection, |
151 | 0 | const typename Collection::key_type& key) { |
152 | 0 | auto it = collection.find(key); |
153 | 0 | if (it == collection.end()) { |
154 | 0 | return 0; |
155 | 0 | } |
156 | 0 | return &it->second; |
157 | 0 | } Unexecuted instantiation: _Z10FindOrNullISt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_St4lessIS6_ESaISt4pairIKS6_S6_EEEEPKNT_11mapped_typeERKSE_RKNSE_8key_typeE Unexecuted instantiation: _Z10FindOrNullISt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES0_IKmN5doris9ThreadMgr16ThreadDescriptorESt4lessIS7_ESaISt4pairIS7_SA_EEESB_IS6_ESaISD_IKS6_SG_EEEEPKNT_11mapped_typeERKSM_RKNSM_8key_typeE |
158 | | |
159 | | // Same as above but returns a pointer to the non-const value. |
160 | | template <class Collection> |
161 | | typename Collection::mapped_type* FindOrNull(Collection& collection, // NOLINT |
162 | | const typename Collection::key_type& key) { |
163 | | auto it = collection.find(key); |
164 | | if (it == collection.end()) { |
165 | | return 0; |
166 | | } |
167 | | return &it->second; |
168 | | } |
169 | | |
170 | | // Returns a pointer to the const value associated with the greatest key |
171 | | // that's less than or equal to the given key, or NULL if no such key exists. |
172 | | template <class Collection> |
173 | | const typename Collection::mapped_type* FindFloorOrNull(const Collection& collection, |
174 | | const typename Collection::key_type& key) { |
175 | | auto it = collection.upper_bound(key); |
176 | | if (it == collection.begin()) { |
177 | | return 0; |
178 | | } |
179 | | return &(--it)->second; |
180 | | } |
181 | | |
182 | | // Same as above but returns a pointer to the non-const value. |
183 | | template <class Collection> |
184 | | typename Collection::mapped_type* FindFloorOrNull(Collection& collection, // NOLINT |
185 | | const typename Collection::key_type& key) { |
186 | | auto it = collection.upper_bound(key); |
187 | | if (it == collection.begin()) { |
188 | | return 0; |
189 | | } |
190 | | return &(--it)->second; |
191 | | } |
192 | | |
193 | | // Returns a const-reference to the value associated with the greatest key |
194 | | // that's less than or equal to the given key, or crashes if it does not exist. |
195 | | template <class Collection> |
196 | | const typename Collection::mapped_type& FindFloorOrDie(const Collection& collection, |
197 | | const typename Collection::key_type& key) { |
198 | | auto it = collection.upper_bound(key); |
199 | | CHECK(it != collection.begin()); |
200 | | return (--it)->second; |
201 | | } |
202 | | |
203 | | // Same as above, but returns a non-const reference. |
204 | | template <class Collection> |
205 | | typename Collection::mapped_type& FindFloorOrDie(Collection& collection, |
206 | | const typename Collection::key_type& key) { |
207 | | auto it = collection.upper_bound(key); |
208 | | CHECK(it != collection.begin()); |
209 | | return (--it)->second; |
210 | | } |
211 | | |
212 | | // Returns the pointer value associated with the given key. If none is found, |
213 | | // NULL is returned. The function is designed to be used with a map of keys to |
214 | | // pointers. |
215 | | // |
216 | | // This function does not distinguish between a missing key and a key mapped |
217 | | // to a NULL value. |
218 | | template <class Collection> |
219 | | typename Collection::mapped_type FindPtrOrNull(const Collection& collection, |
220 | | const typename Collection::key_type& key) { |
221 | | auto it = collection.find(key); |
222 | | if (it == collection.end()) { |
223 | | return typename Collection::mapped_type(0); |
224 | | } |
225 | | return it->second; |
226 | | } |
227 | | |
228 | | // Same as above, except takes non-const reference to collection. |
229 | | // |
230 | | // This function is needed for containers that propagate constness to the |
231 | | // pointee, such as boost::ptr_map. |
232 | | template <class Collection> |
233 | | typename Collection::mapped_type FindPtrOrNull(Collection& collection, // NOLINT |
234 | | const typename Collection::key_type& key) { |
235 | | auto it = collection.find(key); |
236 | | if (it == collection.end()) { |
237 | | return typename Collection::mapped_type(0); |
238 | | } |
239 | | return it->second; |
240 | | } |
241 | | |
242 | | // FindPtrOrNull like function for maps whose value is a smart pointer like shared_ptr or |
243 | | // unique_ptr. |
244 | | // Returns the raw pointer contained in the smart pointer for the first found key, if it exists, |
245 | | // or null if it doesn't. |
246 | | template <class Collection> |
247 | | typename Collection::mapped_type::element_type* FindPointeeOrNull( |
248 | | const Collection& collection, // NOLINT, |
249 | | const typename Collection::key_type& key) { |
250 | | auto it = collection.find(key); |
251 | | if (it == collection.end()) { |
252 | | return nullptr; |
253 | | } |
254 | | return it->second.get(); |
255 | | } |
256 | | |
257 | | // Finds the value associated with the given key and copies it to *value (if not |
258 | | // NULL). Returns false if the key was not found, true otherwise. |
259 | | template <class Collection, class Key, class Value> |
260 | | bool FindCopy(const Collection& collection, const Key& key, Value* const value) { |
261 | | auto it = collection.find(key); |
262 | | if (it == collection.end()) { |
263 | | return false; |
264 | | } |
265 | | if (value) { |
266 | | *value = it->second; |
267 | | } |
268 | | return true; |
269 | | } |
270 | | |
271 | | // |
272 | | // Contains*() |
273 | | // |
274 | | |
275 | | // Returns true iff the given collection contains the given key. |
276 | | template <class Collection, class Key> |
277 | 4.98k | bool ContainsKey(const Collection& collection, const Key& key) { |
278 | 4.98k | return collection.find(key) != collection.end(); |
279 | 4.98k | } |
280 | | |
281 | | // Returns true iff the given collection contains the given key-value pair. |
282 | | template <class Collection, class Key, class Value> |
283 | | bool ContainsKeyValuePair(const Collection& collection, const Key& key, const Value& value) { |
284 | | typedef typename Collection::const_iterator const_iterator; |
285 | | std::pair<const_iterator, const_iterator> range = collection.equal_range(key); |
286 | | for (const_iterator it = range.first; it != range.second; ++it) { |
287 | | if (it->second == value) { |
288 | | return true; |
289 | | } |
290 | | } |
291 | | return false; |
292 | | } |
293 | | |
294 | | // |
295 | | // Insert*() |
296 | | // |
297 | | |
298 | | // Inserts the given key-value pair into the collection. Returns true if the |
299 | | // given key didn't previously exist. If the given key already existed in the |
300 | | // map, its value is changed to the given "value" and false is returned. |
301 | | template <class Collection> |
302 | | bool InsertOrUpdate(Collection* const collection, const typename Collection::value_type& vt) { |
303 | | std::pair<typename Collection::iterator, bool> ret = collection->insert(vt); |
304 | | if (!ret.second) { |
305 | | // update |
306 | | ret.first->second = vt.second; |
307 | | return false; |
308 | | } |
309 | | return true; |
310 | | } |
311 | | |
312 | | // Same as above, except that the key and value are passed separately. |
313 | | template <class Collection> |
314 | | bool InsertOrUpdate(Collection* const collection, const typename Collection::key_type& key, |
315 | | const typename Collection::mapped_type& value) { |
316 | | return InsertOrUpdate(collection, typename Collection::value_type(key, value)); |
317 | | } |
318 | | |
319 | | // Inserts/updates all the key-value pairs from the range defined by the |
320 | | // iterators "first" and "last" into the given collection. |
321 | | template <class Collection, class InputIterator> |
322 | | void InsertOrUpdateMany(Collection* const collection, InputIterator first, InputIterator last) { |
323 | | for (; first != last; ++first) { |
324 | | InsertOrUpdate(collection, *first); |
325 | | } |
326 | | } |
327 | | |
328 | | // Change the value associated with a particular key in a map or hash_map |
329 | | // of the form map<Key, Value*> which owns the objects pointed to by the |
330 | | // value pointers. If there was an existing value for the key, it is deleted. |
331 | | // True indicates an insert took place, false indicates an update + delete. |
332 | | template <class Collection> |
333 | | bool InsertAndDeleteExisting(Collection* const collection, const typename Collection::key_type& key, |
334 | | const typename Collection::mapped_type& value) { |
335 | | std::pair<typename Collection::iterator, bool> ret = |
336 | | collection->insert(typename Collection::value_type(key, value)); |
337 | | if (!ret.second) { |
338 | | delete ret.first->second; |
339 | | ret.first->second = value; |
340 | | return false; |
341 | | } |
342 | | return true; |
343 | | } |
344 | | |
345 | | // Inserts the given key and value into the given collection iff the given key |
346 | | // did NOT already exist in the collection. If the key previously existed in the |
347 | | // collection, the value is not changed. Returns true if the key-value pair was |
348 | | // inserted; returns false if the key was already present. |
349 | | template <class Collection> |
350 | 3.65k | bool InsertIfNotPresent(Collection* const collection, const typename Collection::value_type& vt) { |
351 | 3.65k | return collection->insert(vt).second; |
352 | 3.65k | } _Z18InsertIfNotPresentISt13unordered_setIPN5doris15ThreadPoolTokenESt4hashIS3_ESt8equal_toIS3_ESaIS3_EEEbPT_RKNSA_10value_typeE Line | Count | Source | 350 | 2.24k | bool InsertIfNotPresent(Collection* const collection, const typename Collection::value_type& vt) { | 351 | 2.24k | return collection->insert(vt).second; | 352 | 2.24k | } |
_Z18InsertIfNotPresentISt13unordered_setIPN5doris6ThreadESt4hashIS3_ESt8equal_toIS3_ESaIS3_EEEbPT_RKNSA_10value_typeE Line | Count | Source | 350 | 1.40k | bool InsertIfNotPresent(Collection* const collection, const typename Collection::value_type& vt) { | 351 | 1.40k | return collection->insert(vt).second; | 352 | 1.40k | } |
|
353 | | |
354 | | // Same as above except the key and value are passed separately. |
355 | | template <class Collection> |
356 | | bool InsertIfNotPresent(Collection* const collection, const typename Collection::key_type& key, |
357 | | const typename Collection::mapped_type& value) { |
358 | | return InsertIfNotPresent(collection, typename Collection::value_type(key, value)); |
359 | | } |
360 | | |
361 | | // Same as above except dies if the key already exists in the collection. |
362 | | template <class Collection> |
363 | 3.65k | void InsertOrDie(Collection* const collection, const typename Collection::value_type& value) { |
364 | 3.65k | CHECK(InsertIfNotPresent(collection, value)) << "duplicate value: " << value; |
365 | 3.65k | } _Z11InsertOrDieISt13unordered_setIPN5doris15ThreadPoolTokenESt4hashIS3_ESt8equal_toIS3_ESaIS3_EEEvPT_RKNSA_10value_typeE Line | Count | Source | 363 | 2.24k | void InsertOrDie(Collection* const collection, const typename Collection::value_type& value) { | 364 | 2.24k | CHECK(InsertIfNotPresent(collection, value)) << "duplicate value: " << value; | 365 | 2.24k | } |
_Z11InsertOrDieISt13unordered_setIPN5doris6ThreadESt4hashIS3_ESt8equal_toIS3_ESaIS3_EEEvPT_RKNSA_10value_typeE Line | Count | Source | 363 | 1.40k | void InsertOrDie(Collection* const collection, const typename Collection::value_type& value) { | 364 | 1.40k | CHECK(InsertIfNotPresent(collection, value)) << "duplicate value: " << value; | 365 | 1.40k | } |
|
366 | | |
367 | | // Same as above except doesn't log the value on error. |
368 | | template <class Collection> |
369 | | void InsertOrDieNoPrint(Collection* const collection, |
370 | | const typename Collection::value_type& value) { |
371 | | CHECK(InsertIfNotPresent(collection, value)) << "duplicate value."; |
372 | | } |
373 | | |
374 | | // Inserts the key-value pair into the collection. Dies if key was already |
375 | | // present. |
376 | | template <class Collection> |
377 | | void InsertOrDie(Collection* const collection, const typename Collection::key_type& key, |
378 | | const typename Collection::mapped_type& data) { |
379 | | CHECK(InsertIfNotPresent(collection, key, data)) << "duplicate key: " << key; |
380 | | } |
381 | | |
382 | | // Same as above except deson't log the key on error. |
383 | | template <class Collection> |
384 | | void InsertOrDieNoPrint(Collection* const collection, const typename Collection::key_type& key, |
385 | | const typename Collection::mapped_type& data) { |
386 | | CHECK(InsertIfNotPresent(collection, key, data)) << "duplicate key."; |
387 | | } |
388 | | |
389 | | // Inserts a new key and default-initialized value. Dies if the key was already |
390 | | // present. Returns a reference to the value. Example usage: |
391 | | // |
392 | | // map<int, SomeProto> m; |
393 | | // SomeProto& proto = InsertKeyOrDie(&m, 3); |
394 | | // proto.set_field("foo"); |
395 | | template <class Collection> |
396 | | typename Collection::mapped_type& InsertKeyOrDie(Collection* const collection, |
397 | | const typename Collection::key_type& key) { |
398 | | typedef typename Collection::value_type value_type; |
399 | | std::pair<typename Collection::iterator, bool> res = |
400 | | collection->insert(value_type(key, typename Collection::mapped_type())); |
401 | | CHECK(res.second) << "duplicate key: " << key; |
402 | | return res.first->second; |
403 | | } |
404 | | |
405 | | // |
406 | | // Emplace*() |
407 | | // |
408 | | template <class Collection, class... Args> |
409 | | bool EmplaceIfNotPresent(Collection* const collection, Args&&... args) { |
410 | | return collection->emplace(std::forward<Args>(args)...).second; |
411 | | } |
412 | | |
413 | | // Emplaces the given key-value pair into the collection. Returns true if the |
414 | | // given key didn't previously exist. If the given key already existed in the |
415 | | // map, its value is changed to the given "value" and false is returned. |
416 | | template <class Collection> |
417 | | bool EmplaceOrUpdate(Collection* const collection, const typename Collection::key_type& key, |
418 | | typename Collection::mapped_type&& value) { |
419 | | typedef typename Collection::mapped_type mapped_type; |
420 | | auto it = collection->find(key); |
421 | | if (it == collection->end()) { |
422 | | collection->emplace(key, std::forward<mapped_type>(value)); |
423 | | return true; |
424 | | } |
425 | | it->second = std::forward<mapped_type>(value); |
426 | | return false; |
427 | | } |
428 | | |
429 | | template <class Collection, class... Args> |
430 | | void EmplaceOrDie(Collection* const collection, Args&&... args) { |
431 | | CHECK(EmplaceIfNotPresent(collection, std::forward<Args>(args)...)) << "duplicate value"; |
432 | | } |
433 | | |
434 | | // |
435 | | // Lookup*() |
436 | | // |
437 | | |
438 | | // Looks up a given key and value pair in a collection and inserts the key-value |
439 | | // pair if it's not already present. Returns a reference to the value associated |
440 | | // with the key. |
441 | | template <class Collection> |
442 | | typename Collection::mapped_type& LookupOrInsert(Collection* const collection, |
443 | | const typename Collection::value_type& vt) { |
444 | | return collection->insert(vt).first->second; |
445 | | } |
446 | | |
447 | | // Same as above except the key-value are passed separately. |
448 | | template <class Collection> |
449 | | typename Collection::mapped_type& LookupOrInsert(Collection* const collection, |
450 | | const typename Collection::key_type& key, |
451 | | const typename Collection::mapped_type& value) { |
452 | | return LookupOrInsert(collection, typename Collection::value_type(key, value)); |
453 | | } |
454 | | |
455 | | // It's similar to LookupOrInsert() but uses the emplace and r-value mechanics |
456 | | // to achieve the desired results. The constructor of the new element is called |
457 | | // with exactly the same arguments as supplied to emplace, forwarded via |
458 | | // std::forward<Args>(args). The element may be constructed even if there |
459 | | // already is an element with the same key in the container, in which case the |
460 | | // newly constructed element will be destroyed immediately. |
461 | | // For details, see |
462 | | // https://en.cppreference.com/w/cpp/container/map/emplace |
463 | | // https://en.cppreference.com/w/cpp/container/unordered_map/emplace |
464 | | template <class Collection, class... Args> |
465 | | typename Collection::mapped_type& LookupOrEmplace(Collection* const collection, Args&&... args) { |
466 | | return collection->emplace(std::forward<Args>(args)...).first->second; |
467 | | } |
468 | | |
469 | | // Counts the number of equivalent elements in the given "sequence", and stores |
470 | | // the results in "count_map" with element as the key and count as the value. |
471 | | // |
472 | | // Example: |
473 | | // vector<string> v = {"a", "b", "c", "a", "b"}; |
474 | | // map<string, int> m; |
475 | | // AddTokenCounts(v, 1, &m); |
476 | | // assert(m["a"] == 2); |
477 | | // assert(m["b"] == 2); |
478 | | // assert(m["c"] == 1); |
479 | | template <typename Sequence, typename Collection> |
480 | | void AddTokenCounts(const Sequence& sequence, const typename Collection::mapped_type& increment, |
481 | | Collection* const count_map) { |
482 | | for (typename Sequence::const_iterator it = sequence.begin(); it != sequence.end(); ++it) { |
483 | | typename Collection::mapped_type& value = |
484 | | LookupOrInsert(count_map, *it, typename Collection::mapped_type()); |
485 | | value += increment; |
486 | | } |
487 | | } |
488 | | |
489 | | // Helpers for LookupOrInsertNew(), needed to create a new value type when the |
490 | | // type itself is a pointer, i.e., these extract the actual type from a pointer. |
491 | | template <class T> |
492 | | void MapUtilAssignNewDefaultInstance(T** location) { |
493 | | *location = new T(); |
494 | | } |
495 | | |
496 | | template <class T, class Arg> |
497 | | void MapUtilAssignNewInstance(T** location, const Arg& arg) { |
498 | | *location = new T(arg); |
499 | | } |
500 | | |
501 | | // Returns a reference to the value associated with key. If not found, a value |
502 | | // is default constructed on the heap and added to the map. |
503 | | // |
504 | | // This function is useful for containers of the form map<Key, Value*>, where |
505 | | // inserting a new key, value pair involves constructing a new heap-allocated |
506 | | // Value, and storing a pointer to that in the collection. |
507 | | template <class Collection> |
508 | | typename Collection::mapped_type& LookupOrInsertNew(Collection* const collection, |
509 | | const typename Collection::key_type& key) { |
510 | | std::pair<typename Collection::iterator, bool> ret = |
511 | | collection->insert(typename Collection::value_type( |
512 | | key, static_cast<typename Collection::mapped_type>(NULL))); |
513 | | if (ret.second) { |
514 | | // This helper is needed to 'extract' the Value type from the type of the |
515 | | // container value, which is (Value*). |
516 | | MapUtilAssignNewDefaultInstance(&(ret.first->second)); |
517 | | } |
518 | | return ret.first->second; |
519 | | } |
520 | | |
521 | | // Same as above but constructs the value using the single-argument constructor |
522 | | // and the given "arg". |
523 | | template <class Collection, class Arg> |
524 | | typename Collection::mapped_type& LookupOrInsertNew(Collection* const collection, |
525 | | const typename Collection::key_type& key, |
526 | | const Arg& arg) { |
527 | | std::pair<typename Collection::iterator, bool> ret = |
528 | | collection->insert(typename Collection::value_type( |
529 | | key, static_cast<typename Collection::mapped_type>(NULL))); |
530 | | if (ret.second) { |
531 | | // This helper is needed to 'extract' the Value type from the type of the |
532 | | // container value, which is (Value*). |
533 | | MapUtilAssignNewInstance(&(ret.first->second), arg); |
534 | | } |
535 | | return ret.first->second; |
536 | | } |
537 | | |
538 | | // Lookup of linked/shared pointers is used in two scenarios: |
539 | | // |
540 | | // Use LookupOrInsertSharedPtr if the container does not own the elements |
541 | | // for their whole lifetime. This is typically the case when a reader allows |
542 | | // parallel updates to the container. In this case a Mutex only needs to lock |
543 | | // container operations, but all element operations must be performed on the |
544 | | // shared pointer. Finding an element must be performed using FindPtr*() and |
545 | | // cannot be done with FindLinkedPtr*() even though it compiles. |
546 | | |
547 | | // Lookup a key in a map or hash_map whose values are shared_ptrs. If it is |
548 | | // missing, set collection[key].reset(new Value::element_type). Unlike |
549 | | // LookupOrInsertNewLinkedPtr, this function returns the shared_ptr instead of |
550 | | // the raw pointer. Value::element_type must be default constructable. |
551 | | template <class Collection> |
552 | | typename Collection::mapped_type& LookupOrInsertNewSharedPtr( |
553 | | Collection* const collection, const typename Collection::key_type& key) { |
554 | | typedef typename Collection::mapped_type SharedPtr; |
555 | | typedef typename Collection::mapped_type::element_type Element; |
556 | | std::pair<typename Collection::iterator, bool> ret = |
557 | | collection->insert(typename Collection::value_type(key, SharedPtr())); |
558 | | if (ret.second) { |
559 | | ret.first->second.reset(new Element()); |
560 | | } |
561 | | return ret.first->second; |
562 | | } |
563 | | |
564 | | // A variant of LookupOrInsertNewSharedPtr where the value is constructed using |
565 | | // a single-parameter constructor. Note: the constructor argument is computed |
566 | | // even if it will not be used, so only values cheap to compute should be passed |
567 | | // here. On the other hand it does not matter how expensive the construction of |
568 | | // the actual stored value is, as that only occurs if necessary. |
569 | | template <class Collection, class Arg> |
570 | | typename Collection::mapped_type& LookupOrInsertNewSharedPtr( |
571 | | Collection* const collection, const typename Collection::key_type& key, const Arg& arg) { |
572 | | typedef typename Collection::mapped_type SharedPtr; |
573 | | typedef typename Collection::mapped_type::element_type Element; |
574 | | std::pair<typename Collection::iterator, bool> ret = |
575 | | collection->insert(typename Collection::value_type(key, SharedPtr())); |
576 | | if (ret.second) { |
577 | | ret.first->second.reset(new Element(arg)); |
578 | | } |
579 | | return ret.first->second; |
580 | | } |
581 | | |
582 | | // |
583 | | // Misc Utility Functions |
584 | | // |
585 | | |
586 | | // Updates the value associated with the given key. If the key was not already |
587 | | // present, then the key-value pair are inserted and "previous" is unchanged. If |
588 | | // the key was already present, the value is updated and "*previous" will |
589 | | // contain a copy of the old value. |
590 | | // |
591 | | // InsertOrReturnExisting has complementary behavior that returns the |
592 | | // address of an already existing value, rather than updating it. |
593 | | template <class Collection> |
594 | | bool UpdateReturnCopy(Collection* const collection, const typename Collection::key_type& key, |
595 | | const typename Collection::mapped_type& value, |
596 | | typename Collection::mapped_type* previous) { |
597 | | std::pair<typename Collection::iterator, bool> ret = |
598 | | collection->insert(typename Collection::value_type(key, value)); |
599 | | if (!ret.second) { |
600 | | // update |
601 | | if (previous) { |
602 | | *previous = ret.first->second; |
603 | | } |
604 | | ret.first->second = value; |
605 | | return true; |
606 | | } |
607 | | return false; |
608 | | } |
609 | | |
610 | | // Same as above except that the key and value are passed as a pair. |
611 | | template <class Collection> |
612 | | bool UpdateReturnCopy(Collection* const collection, const typename Collection::value_type& vt, |
613 | | typename Collection::mapped_type* previous) { |
614 | | std::pair<typename Collection::iterator, bool> ret = collection->insert(vt); |
615 | | if (!ret.second) { |
616 | | // update |
617 | | if (previous) { |
618 | | *previous = ret.first->second; |
619 | | } |
620 | | ret.first->second = vt.second; |
621 | | return true; |
622 | | } |
623 | | return false; |
624 | | } |
625 | | |
626 | | // Tries to insert the given key-value pair into the collection. Returns NULL if |
627 | | // the insert succeeds. Otherwise, returns a pointer to the existing value. |
628 | | // |
629 | | // This complements UpdateReturnCopy in that it allows to update only after |
630 | | // verifying the old value and still insert quickly without having to look up |
631 | | // twice. Unlike UpdateReturnCopy this also does not come with the issue of an |
632 | | // undefined previous* in case new data was inserted. |
633 | | template <class Collection> |
634 | | typename Collection::mapped_type* InsertOrReturnExisting( |
635 | | Collection* const collection, const typename Collection::value_type& vt) { |
636 | | std::pair<typename Collection::iterator, bool> ret = collection->insert(vt); |
637 | | if (ret.second) { |
638 | | return NULL; // Inserted, no existing previous value. |
639 | | } else { |
640 | | return &ret.first->second; // Return address of already existing value. |
641 | | } |
642 | | } |
643 | | |
644 | | // Same as above, except for explicit key and data. |
645 | | template <class Collection> |
646 | | typename Collection::mapped_type* InsertOrReturnExisting( |
647 | | Collection* const collection, const typename Collection::key_type& key, |
648 | | const typename Collection::mapped_type& data) { |
649 | | return InsertOrReturnExisting(collection, typename Collection::value_type(key, data)); |
650 | | } |
651 | | |
652 | | // Saves the reverse mapping into reverse. Key/value pairs are inserted in the |
653 | | // order the iterator returns them. |
654 | | template <class Collection, class ReverseCollection> |
655 | | void ReverseMap(const Collection& collection, ReverseCollection* const reverse) { |
656 | | CHECK(reverse != NULL); |
657 | | for (typename Collection::const_iterator it = collection.begin(); it != collection.end(); |
658 | | ++it) { |
659 | | InsertOrUpdate(reverse, it->second, it->first); |
660 | | } |
661 | | } |
662 | | |
663 | | // Erases the collection item identified by the given key, and returns the value |
664 | | // associated with that key. It is assumed that the value (i.e., the |
665 | | // mapped_type) is a pointer. Returns NULL if the key was not found in the |
666 | | // collection. |
667 | | // |
668 | | // Examples: |
669 | | // map<string, MyType*> my_map; |
670 | | // |
671 | | // One line cleanup: |
672 | | // delete EraseKeyReturnValuePtr(&my_map, "abc"); |
673 | | // |
674 | | // Use returned value: |
675 | | // gscoped_ptr<MyType> value_ptr(EraseKeyReturnValuePtr(&my_map, "abc")); |
676 | | // if (value_ptr.get()) |
677 | | // value_ptr->DoSomething(); |
678 | | // |
679 | | // Note: if 'collection' is a multimap, this will only erase and return the |
680 | | // first value. |
681 | | template <class Collection> |
682 | | typename Collection::mapped_type EraseKeyReturnValuePtr(Collection* const collection, |
683 | | const typename Collection::key_type& key) { |
684 | | auto it = collection->find(key); |
685 | | if (it == collection->end()) { |
686 | | return typename Collection::mapped_type(); |
687 | | } |
688 | | typename Collection::mapped_type v = std::move(it->second); |
689 | | collection->erase(it); |
690 | | return v; |
691 | | } |
692 | | |
693 | | // Inserts all the keys from map_container into key_container, which must |
694 | | // support insert(MapContainer::key_type). |
695 | | // |
696 | | // Note: any initial contents of the key_container are not cleared. |
697 | | template <class MapContainer, class KeyContainer> |
698 | | void InsertKeysFromMap(const MapContainer& map_container, KeyContainer* key_container) { |
699 | | CHECK(key_container != NULL); |
700 | | for (typename MapContainer::const_iterator it = map_container.begin(); |
701 | | it != map_container.end(); ++it) { |
702 | | key_container->insert(it->first); |
703 | | } |
704 | | } |
705 | | |
706 | | // Appends all the keys from map_container into key_container, which must |
707 | | // support push_back(MapContainer::key_type). |
708 | | // |
709 | | // Note: any initial contents of the key_container are not cleared. |
710 | | template <class MapContainer, class KeyContainer> |
711 | | void AppendKeysFromMap(const MapContainer& map_container, KeyContainer* key_container) { |
712 | | CHECK(key_container != NULL); |
713 | | for (typename MapContainer::const_iterator it = map_container.begin(); |
714 | | it != map_container.end(); ++it) { |
715 | | key_container->push_back(it->first); |
716 | | } |
717 | | } |
718 | | |
719 | | // A more specialized overload of AppendKeysFromMap to optimize reallocations |
720 | | // for the common case in which we're appending keys to a vector and hence can |
721 | | // (and sometimes should) call reserve() first. |
722 | | // |
723 | | // (It would be possible to play SFINAE games to call reserve() for any |
724 | | // container that supports it, but this seems to get us 99% of what we need |
725 | | // without the complexity of a SFINAE-based solution.) |
726 | | template <class MapContainer, class KeyType> |
727 | | void AppendKeysFromMap(const MapContainer& map_container, std::vector<KeyType>* key_container) { |
728 | | CHECK(key_container != NULL); |
729 | | // We now have the opportunity to call reserve(). Calling reserve() every |
730 | | // time is a bad idea for some use cases: libstdc++'s implementation of |
731 | | // vector<>::reserve() resizes the vector's backing store to exactly the |
732 | | // given size (unless it's already at least that big). Because of this, |
733 | | // the use case that involves appending a lot of small maps (total size |
734 | | // N) one by one to a vector would be O(N^2). But never calling reserve() |
735 | | // loses the opportunity to improve the use case of adding from a large |
736 | | // map to an empty vector (this improves performance by up to 33%). A |
737 | | // number of heuristics are possible; see the discussion in |
738 | | // cl/34081696. Here we use the simplest one. |
739 | | if (key_container->empty()) { |
740 | | key_container->reserve(map_container.size()); |
741 | | } |
742 | | for (typename MapContainer::const_iterator it = map_container.begin(); |
743 | | it != map_container.end(); ++it) { |
744 | | key_container->push_back(it->first); |
745 | | } |
746 | | } |
747 | | |
748 | | // Inserts all the values from map_container into value_container, which must |
749 | | // support push_back(MapContainer::mapped_type). |
750 | | // |
751 | | // Note: any initial contents of the value_container are not cleared. |
752 | | template <class MapContainer, class ValueContainer> |
753 | | void AppendValuesFromMap(const MapContainer& map_container, ValueContainer* value_container) { |
754 | | CHECK(value_container != NULL); |
755 | | for (typename MapContainer::const_iterator it = map_container.begin(); |
756 | | it != map_container.end(); ++it) { |
757 | | value_container->push_back(it->second); |
758 | | } |
759 | | } |
760 | | |
761 | | template <class MapContainer, class ValueContainer> |
762 | | void EmplaceValuesFromMap(MapContainer&& map_container, ValueContainer* value_container) { |
763 | | CHECK(value_container != nullptr); |
764 | | // See AppendKeysFromMap for why this is done. |
765 | | if (value_container->empty()) { |
766 | | value_container->reserve(map_container.size()); |
767 | | } |
768 | | for (auto&& entry : map_container) { |
769 | | value_container->emplace_back(std::move(entry.second)); |
770 | | } |
771 | | } |
772 | | |
773 | | // A more specialized overload of AppendValuesFromMap to optimize reallocations |
774 | | // for the common case in which we're appending values to a vector and hence |
775 | | // can (and sometimes should) call reserve() first. |
776 | | // |
777 | | // (It would be possible to play SFINAE games to call reserve() for any |
778 | | // container that supports it, but this seems to get us 99% of what we need |
779 | | // without the complexity of a SFINAE-based solution.) |
780 | | template <class MapContainer, class ValueType> |
781 | | void AppendValuesFromMap(const MapContainer& map_container, |
782 | | std::vector<ValueType>* value_container) { |
783 | | EmplaceValuesFromMap(map_container, value_container); |
784 | | } |
785 | | |
786 | | // Compute and insert new value if it's absent from the map. Return a pair with a reference to the |
787 | | // value and a bool indicating whether it was absent at first. |
788 | | // |
789 | | // This inspired on a similar java construct (url split in two lines): |
790 | | // https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html |
791 | | // #computeIfAbsent-K-java.util.function.Function |
792 | | // |
793 | | // It takes a reference to the key and a lambda function. If the key exists in the map, returns |
794 | | // a pair with a pointer to the current value and 'false'. If the key does not exist in the map, |
795 | | // it uses the lambda function to create a value, inserts it into the map, and returns a pair with |
796 | | // a pointer to the new value and 'true'. |
797 | | // |
798 | | // Example usage: |
799 | | // |
800 | | // auto result = ComputeIfAbsentReturnAbsense(&my_collection, |
801 | | // my_key, |
802 | | // [] { return new_value; }); |
803 | | // MyValue* const value = result.first; |
804 | | // if (result.second) .... |
805 | | // |
806 | | // The ComputePair* variants expect a lambda that creates a pair<k, v>. This |
807 | | // can be useful if the key is a StringPiece pointing to external state to |
808 | | // avoid excess memory for the keys, while being safer in multi-threaded |
809 | | // contexts, e.g. in case the key goes out of scope before the container does. |
810 | | // |
811 | | // Example usage: |
812 | | // |
813 | | // map<StringPiece, int, GoodFastHash<StringPiece>> string_to_idx; |
814 | | // vector<unique_ptr<StringPB>> pbs; |
815 | | // auto result = ComputePairIfAbsentReturnAbsense(&string_to_idx, my_key, |
816 | | // [&]() { |
817 | | // unique_ptr<StringPB> s = new StringPB(); |
818 | | // s->set_string(my_key); |
819 | | // int idx = pbs.size(); |
820 | | // pbs.emplace_back(s.release()); |
821 | | // return make_pair(StringPiece(pbs.back()->string()), idx); |
822 | | // }); |
823 | | template <class MapContainer, typename Function> |
824 | | std::pair<typename MapContainer::mapped_type* const, bool> ComputePairIfAbsentReturnAbsense( |
825 | | MapContainer* container, const typename MapContainer::key_type& key, |
826 | | Function compute_pair_func) { |
827 | | typename MapContainer::iterator iter = container->find(key); |
828 | | bool new_value = iter == container->end(); |
829 | | if (new_value) { |
830 | | auto p = compute_pair_func(); |
831 | | std::pair<typename MapContainer::iterator, bool> result = |
832 | | container->emplace(std::move(p.first), std::move(p.second)); |
833 | | DCHECK(result.second) << "duplicate key: " << key; |
834 | | iter = result.first; |
835 | | } |
836 | | return std::make_pair(&iter->second, new_value); |
837 | | } |
838 | | template <class MapContainer, typename Function> |
839 | | std::pair<typename MapContainer::mapped_type* const, bool> ComputeIfAbsentReturnAbsense( |
840 | | MapContainer* container, const typename MapContainer::key_type& key, |
841 | | Function compute_func) { |
842 | | return ComputePairIfAbsentReturnAbsense( |
843 | | container, key, [&key, &compute_func] { return std::make_pair(key, compute_func()); }); |
844 | | }; |
845 | | |
846 | | // Like the above but doesn't return a pair, just returns a pointer to the value. |
847 | | // Example usage: |
848 | | // |
849 | | // MyValue* const value = ComputeIfAbsent(&my_collection, |
850 | | // my_key, |
851 | | // [] { return new_value; }); |
852 | | // |
853 | | template <class MapContainer, typename Function> |
854 | | typename MapContainer::mapped_type* ComputeIfAbsent(MapContainer* container, |
855 | | const typename MapContainer::key_type& key, |
856 | | Function compute_func) { |
857 | | return ComputeIfAbsentReturnAbsense(container, key, compute_func).first; |
858 | | }; |
859 | | |
860 | | template <class MapContainer, typename Function> |
861 | | typename MapContainer::mapped_type* ComputePairIfAbsent(MapContainer* container, |
862 | | const typename MapContainer::key_type& key, |
863 | | Function compute_pair_func) { |
864 | | return ComputePairIfAbsentReturnAbsense<MapContainer, Function>(container, key, |
865 | | compute_pair_func) |
866 | | .first; |
867 | | }; |