Coverage Report

Created: 2024-11-22 21:49

/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.62k
bool ContainsKey(const Collection& collection, const Key& key) {
278
4.62k
    return collection.find(key) != collection.end();
279
4.62k
}
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.49k
bool InsertIfNotPresent(Collection* const collection, const typename Collection::value_type& vt) {
351
3.49k
    return collection->insert(vt).second;
352
3.49k
}
_Z18InsertIfNotPresentISt13unordered_setIPN5doris15ThreadPoolTokenESt4hashIS3_ESt8equal_toIS3_ESaIS3_EEEbPT_RKNSA_10value_typeE
Line
Count
Source
350
2.09k
bool InsertIfNotPresent(Collection* const collection, const typename Collection::value_type& vt) {
351
2.09k
    return collection->insert(vt).second;
352
2.09k
}
_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.49k
void InsertOrDie(Collection* const collection, const typename Collection::value_type& value) {
364
3.49k
    CHECK(InsertIfNotPresent(collection, value)) << "duplicate value: " << value;
365
3.49k
}
_Z11InsertOrDieISt13unordered_setIPN5doris15ThreadPoolTokenESt4hashIS3_ESt8equal_toIS3_ESaIS3_EEEvPT_RKNSA_10value_typeE
Line
Count
Source
363
2.09k
void InsertOrDie(Collection* const collection, const typename Collection::value_type& value) {
364
2.09k
    CHECK(InsertIfNotPresent(collection, value)) << "duplicate value: " << value;
365
2.09k
}
_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
};