/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()) {  Branch (153:9): [True: 0, False: 0]
  Branch (153:9): [True: 0, False: 0]
 | 
| 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_typeEUnexecuted 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.90k | bool ContainsKey(const Collection& collection, const Key& key) { | 
| 278 | 4.90k |     return collection.find(key) != collection.end(); | 
| 279 | 4.90k | } | 
| 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.66k | bool InsertIfNotPresent(Collection* const collection, const typename Collection::value_type& vt) { | 
| 351 | 3.66k |     return collection->insert(vt).second; | 
| 352 | 3.66k | } _Z18InsertIfNotPresentISt13unordered_setIPN5doris15ThreadPoolTokenESt4hashIS3_ESt8equal_toIS3_ESaIS3_EEEbPT_RKNSA_10value_typeE| Line | Count | Source |  | 350 | 2.19k | bool InsertIfNotPresent(Collection* const collection, const typename Collection::value_type& vt) { |  | 351 | 2.19k |     return collection->insert(vt).second; |  | 352 | 2.19k | } | 
_Z18InsertIfNotPresentISt13unordered_setIPN5doris6ThreadESt4hashIS3_ESt8equal_toIS3_ESaIS3_EEEbPT_RKNSA_10value_typeE| Line | Count | Source |  | 350 | 1.46k | bool InsertIfNotPresent(Collection* const collection, const typename Collection::value_type& vt) { |  | 351 | 1.46k |     return collection->insert(vt).second; |  | 352 | 1.46k | } | 
 | 
| 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.66k | void InsertOrDie(Collection* const collection, const typename Collection::value_type& value) { | 
| 364 | 3.66k |     CHECK(InsertIfNotPresent(collection, value)) << "duplicate value: " << value; | 
| 365 | 3.66k | } _Z11InsertOrDieISt13unordered_setIPN5doris15ThreadPoolTokenESt4hashIS3_ESt8equal_toIS3_ESaIS3_EEEvPT_RKNSA_10value_typeE| Line | Count | Source |  | 363 | 2.19k | void InsertOrDie(Collection* const collection, const typename Collection::value_type& value) { |  | 364 | 2.19k |     CHECK(InsertIfNotPresent(collection, value)) << "duplicate value: " << value; |  | 365 | 2.19k | } | 
_Z11InsertOrDieISt13unordered_setIPN5doris6ThreadESt4hashIS3_ESt8equal_toIS3_ESaIS3_EEEvPT_RKNSA_10value_typeE| Line | Count | Source |  | 363 | 1.46k | void InsertOrDie(Collection* const collection, const typename Collection::value_type& value) { |  | 364 | 1.46k |     CHECK(InsertIfNotPresent(collection, value)) << "duplicate value: " << value; |  | 365 | 1.46k | } | 
 | 
| 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 |  | }; |