/root/doris/be/src/gutil/stl_util.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2002 Google Inc. |
2 | | // |
3 | | // Licensed to the Apache Software Foundation (ASF) under one |
4 | | // or more contributor license agreements. See the NOTICE file |
5 | | // distributed with this work for additional information |
6 | | // regarding copyright ownership. The ASF licenses this file |
7 | | // to you under the Apache License, Version 2.0 (the |
8 | | // "License"); you may not use this file except in compliance |
9 | | // with the License. You may obtain a copy of the License at |
10 | | // |
11 | | // http://www.apache.org/licenses/LICENSE-2.0 |
12 | | // |
13 | | // Unless required by applicable law or agreed to in writing, |
14 | | // software distributed under the License is distributed on an |
15 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
16 | | // KIND, either express or implied. See the License for the |
17 | | // specific language governing permissions and limitations |
18 | | // under the License. |
19 | | // |
20 | | // --- |
21 | | // |
22 | | // |
23 | | // STL utility functions. Usually, these replace built-in, but slow(!), |
24 | | // STL functions with more efficient versions or provide a more convenient |
25 | | // and Google friendly API. |
26 | | // |
27 | | |
28 | | #pragma once |
29 | | |
30 | | #include <stddef.h> |
31 | | #include <string.h> // for memcpy |
32 | | |
33 | | #include <algorithm> |
34 | | using std::copy; |
35 | | using std::max; |
36 | | using std::min; |
37 | | using std::reverse; |
38 | | using std::sort; |
39 | | using std::swap; |
40 | | #include <cassert> |
41 | | #include <deque> |
42 | | using std::deque; |
43 | | #include <functional> |
44 | | using std::less; |
45 | | #include <iterator> |
46 | | using std::back_insert_iterator; |
47 | | using std::iterator_traits; |
48 | | #include <memory> |
49 | | #include <string> |
50 | | using std::string; |
51 | | #include <vector> |
52 | | using std::vector; |
53 | | |
54 | | #include "gutil/integral_types.h" |
55 | | #include "gutil/macros.h" |
56 | | #include "gutil/port.h" |
57 | | |
58 | | // Sort and remove duplicates of an STL vector or deque. |
59 | | template <class T> |
60 | | void STLSortAndRemoveDuplicates(T* v) { |
61 | | sort(v->begin(), v->end()); |
62 | | v->erase(unique(v->begin(), v->end()), v->end()); |
63 | | } |
64 | | |
65 | | // Clear internal memory of an STL object. |
66 | | // STL clear()/reserve(0) does not always free internal memory allocated |
67 | | // This function uses swap/destructor to ensure the internal memory is freed. |
68 | | template <class T> |
69 | | void STLClearObject(T* obj) { |
70 | | T tmp; |
71 | | tmp.swap(*obj); |
72 | | obj->reserve(0); // this is because sometimes "T tmp" allocates objects with |
73 | | // memory (arena implementation?). use reserve() |
74 | | // to clear() even if it doesn't always work |
75 | | } |
76 | | |
77 | | // Specialization for deque. Same as STLClearObject but doesn't call reserve |
78 | | // since deque doesn't have reserve. |
79 | | template <class T, class A> |
80 | | void STLClearObject(deque<T, A>* obj) { |
81 | | deque<T, A> tmp; |
82 | | tmp.swap(*obj); |
83 | | } |
84 | | |
85 | | // Reduce memory usage on behalf of object if its capacity is greater |
86 | | // than or equal to "limit", which defaults to 2^20. |
87 | | template <class T> |
88 | | void STLClearIfBig(T* obj, size_t limit = 1 << 20) { |
89 | | if (obj->capacity() >= limit) { |
90 | | STLClearObject(obj); |
91 | | } else { |
92 | | obj->clear(); |
93 | | } |
94 | | } |
95 | | |
96 | | // Specialization for deque, which doesn't implement capacity(). |
97 | | template <class T, class A> |
98 | | void STLClearIfBig(deque<T, A>* obj, size_t limit = 1 << 20) { |
99 | | if (obj->size() >= limit) { |
100 | | STLClearObject(obj); |
101 | | } else { |
102 | | obj->clear(); |
103 | | } |
104 | | } |
105 | | |
106 | | // Reduce the number of buckets in a hash_set or hash_map back to the |
107 | | // default if the current number of buckets is "limit" or more. |
108 | | // |
109 | | // Suppose you repeatedly fill and clear a hash_map or hash_set. If |
110 | | // you ever insert a lot of items, then your hash table will have lots |
111 | | // of buckets thereafter. (The number of buckets is not reduced when |
112 | | // the table is cleared.) Having lots of buckets is good if you |
113 | | // insert comparably many items in every iteration, because you'll |
114 | | // reduce collisions and table resizes. But having lots of buckets is |
115 | | // bad if you insert few items in most subsequent iterations, because |
116 | | // repeatedly clearing out all those buckets can get expensive. |
117 | | // |
118 | | // One solution is to call STLClearHashIfBig() with a "limit" value |
119 | | // that is a small multiple of the typical number of items in your |
120 | | // table. In the common case, this is equivalent to an ordinary |
121 | | // clear. In the rare case where you insert a lot of items, the |
122 | | // number of buckets is reset to the default to keep subsequent clear |
123 | | // operations cheap. Note that the default number of buckets is 193 |
124 | | // in the Gnu library implementation as of Jan '08. |
125 | | template <class T> |
126 | | void STLClearHashIfBig(T* obj, size_t limit) { |
127 | | if (obj->bucket_count() >= limit) { |
128 | | T tmp; |
129 | | tmp.swap(*obj); |
130 | | } else { |
131 | | obj->clear(); |
132 | | } |
133 | | } |
134 | | |
135 | | // Reserve space for STL object. |
136 | | // STL's reserve() will always copy. |
137 | | // This function avoid the copy if we already have capacity |
138 | | template <class T> |
139 | | void STLReserveIfNeeded(T* obj, int new_size) { |
140 | | if (obj->capacity() < new_size) // increase capacity |
141 | | obj->reserve(new_size); |
142 | | else if (obj->size() > new_size) // reduce size |
143 | | obj->resize(new_size); |
144 | | } |
145 | | |
146 | | // STLDeleteContainerPointers() |
147 | | // For a range within a container of pointers, calls delete |
148 | | // (non-array version) on these pointers. |
149 | | // NOTE: for these three functions, we could just implement a DeleteObject |
150 | | // functor and then call for_each() on the range and functor, but this |
151 | | // requires us to pull in all of <algorithm>, which seems expensive. |
152 | | // For hash_[multi]set, it is important that this deletes behind the iterator |
153 | | // because the hash_set may call the hash function on the iterator when it is |
154 | | // advanced, which could result in the hash function trying to deference a |
155 | | // stale pointer. |
156 | | // NOTE: If you're calling this on an entire container, you probably want |
157 | | // to call STLDeleteElements(&container) instead, or use an ElementDeleter. |
158 | | template <class ForwardIterator> |
159 | | void STLDeleteContainerPointers(ForwardIterator begin, ForwardIterator end) { |
160 | | while (begin != end) { |
161 | | ForwardIterator temp = begin; |
162 | | ++begin; |
163 | | delete *temp; |
164 | | } |
165 | | } |
166 | | |
167 | | // STLDeleteContainerPairPointers() |
168 | | // For a range within a container of pairs, calls delete |
169 | | // (non-array version) on BOTH items in the pairs. |
170 | | // NOTE: Like STLDeleteContainerPointers, it is important that this deletes |
171 | | // behind the iterator because if both the key and value are deleted, the |
172 | | // container may call the hash function on the iterator when it is advanced, |
173 | | // which could result in the hash function trying to dereference a stale |
174 | | // pointer. |
175 | | template <class ForwardIterator> |
176 | | void STLDeleteContainerPairPointers(ForwardIterator begin, ForwardIterator end) { |
177 | | while (begin != end) { |
178 | | ForwardIterator temp = begin; |
179 | | ++begin; |
180 | | delete temp->first; |
181 | | delete temp->second; |
182 | | } |
183 | | } |
184 | | |
185 | | // STLDeleteContainerPairFirstPointers() |
186 | | // For a range within a container of pairs, calls delete (non-array version) |
187 | | // on the FIRST item in the pairs. |
188 | | // NOTE: Like STLDeleteContainerPointers, deleting behind the iterator. |
189 | | template <class ForwardIterator> |
190 | | void STLDeleteContainerPairFirstPointers(ForwardIterator begin, ForwardIterator end) { |
191 | | while (begin != end) { |
192 | | ForwardIterator temp = begin; |
193 | | ++begin; |
194 | | delete temp->first; |
195 | | } |
196 | | } |
197 | | |
198 | | // STLDeleteContainerPairSecondPointers() |
199 | | // For a range within a container of pairs, calls delete |
200 | | // (non-array version) on the SECOND item in the pairs. |
201 | | // NOTE: Like STLDeleteContainerPointers, deleting behind the iterator. |
202 | | // Deleting the value does not always invalidate the iterator, but it may |
203 | | // do so if the key is a pointer into the value object. |
204 | | // NOTE: If you're calling this on an entire container, you probably want |
205 | | // to call STLDeleteValues(&container) instead, or use ValueDeleter. |
206 | | template <class ForwardIterator> |
207 | 1 | void STLDeleteContainerPairSecondPointers(ForwardIterator begin, ForwardIterator end) { |
208 | 10 | while (begin != end) { |
209 | 9 | ForwardIterator temp = begin; |
210 | 9 | ++begin; |
211 | 9 | delete temp->second; |
212 | 9 | } |
213 | 1 | } |
214 | | |
215 | | template <typename T> |
216 | 0 | inline void STLAssignToVector(vector<T>* vec, const T* ptr, size_t n) { |
217 | 0 | vec->resize(n); |
218 | 0 | if (n == 0) return; |
219 | 0 | memcpy(&vec->front(), ptr, n * sizeof(T)); |
220 | 0 | } |
221 | | |
222 | | // Not faster; but we need the specialization so the function works at all |
223 | | // on the vector<bool> specialization. |
224 | | template <> |
225 | 0 | inline void STLAssignToVector(vector<bool>* vec, const bool* ptr, size_t n) { |
226 | 0 | vec->clear(); |
227 | 0 | if (n == 0) return; |
228 | 0 | vec->insert(vec->begin(), ptr, ptr + n); |
229 | 0 | } |
230 | | |
231 | | /***** Hack to allow faster assignment to a vector *****/ |
232 | | |
233 | | // This routine speeds up an assignment of 32 bytes to a vector from |
234 | | // about 250 cycles per assignment to about 140 cycles. |
235 | | // |
236 | | // Usage: |
237 | | // STLAssignToVectorChar(&vec, ptr, size); |
238 | | // STLAssignToString(&str, ptr, size); |
239 | | |
240 | 0 | inline void STLAssignToVectorChar(vector<char>* vec, const char* ptr, size_t n) { |
241 | 0 | STLAssignToVector(vec, ptr, n); |
242 | 0 | } |
243 | | |
244 | | // A struct that mirrors the GCC4 implementation of a string. See: |
245 | | // /usr/crosstool/v8/gcc-4.1.0-glibc-2.2.2/i686-unknown-linux-gnu/include/c++/4.1.0/ext/sso_string_base.h |
246 | | struct InternalStringRepGCC4 { |
247 | | char* _M_data = nullptr; |
248 | | size_t _M_string_length; |
249 | | |
250 | | enum { _S_local_capacity = 15 }; |
251 | | |
252 | | union { |
253 | | char _M_local_data[_S_local_capacity + 1]; |
254 | | size_t _M_allocated_capacity; |
255 | | }; |
256 | | }; |
257 | | |
258 | | // Like str->resize(new_size), except any new characters added to |
259 | | // "*str" as a result of resizing may be left uninitialized, rather |
260 | | // than being filled with '0' bytes. Typically used when code is then |
261 | | // going to overwrite the backing store of the string with known data. |
262 | 114k | inline void STLStringResizeUninitialized(string* s, size_t new_size) { |
263 | 114k | if (sizeof(*s) == sizeof(InternalStringRepGCC4)) { |
264 | 114k | if (new_size > s->capacity()) { |
265 | 3.23k | s->reserve(new_size); |
266 | 3.23k | } |
267 | | // The line below depends on the layout of 'string'. THIS IS |
268 | | // NON-PORTABLE CODE. If our STL implementation changes, we will |
269 | | // need to change this as well. |
270 | 114k | InternalStringRepGCC4* rep = reinterpret_cast<InternalStringRepGCC4*>(s); |
271 | 114k | assert(rep->_M_data == s->data()); |
272 | 0 | assert(rep->_M_string_length == s->size()); |
273 | | |
274 | | // We have to null-terminate the string for c_str() to work properly. |
275 | | // So we leave the actual contents of the string uninitialized, but |
276 | | // we set the byte one past the new end of the string to '\0' |
277 | 0 | const_cast<char*>(s->data())[new_size] = '\0'; |
278 | 114k | rep->_M_string_length = new_size; |
279 | 114k | } else { |
280 | | // Slow path: have to reallocate stuff, or an unknown string rep |
281 | 0 | s->resize(new_size); |
282 | 0 | } |
283 | 114k | } |
284 | | |
285 | | // Returns true if the string implementation supports a resize where |
286 | | // the new characters added to the string are left untouched. |
287 | 0 | inline bool STLStringSupportsNontrashingResize(const string& s) { |
288 | 0 | return (sizeof(s) == sizeof(InternalStringRepGCC4)); |
289 | 0 | } |
290 | | |
291 | 0 | inline void STLAssignToString(string* str, const char* ptr, size_t n) { |
292 | 0 | STLStringResizeUninitialized(str, n); |
293 | 0 | if (n == 0) return; |
294 | 0 | memcpy(&*str->begin(), ptr, n); |
295 | 0 | } |
296 | | |
297 | 0 | inline void STLAppendToString(string* str, const char* ptr, size_t n) { |
298 | 0 | if (n == 0) return; |
299 | 0 | size_t old_size = str->size(); |
300 | 0 | STLStringResizeUninitialized(str, old_size + n); |
301 | 0 | memcpy(&*str->begin() + old_size, ptr, n); |
302 | 0 | } |
303 | | |
304 | | // To treat a possibly-empty vector as an array, use these functions. |
305 | | // If you know the array will never be empty, you can use &*v.begin() |
306 | | // directly, but that is allowed to dump core if v is empty. This |
307 | | // function is the most efficient code that will work, taking into |
308 | | // account how our STL is actually implemented. THIS IS NON-PORTABLE |
309 | | // CODE, so call us instead of repeating the nonportable code |
310 | | // everywhere. If our STL implementation changes, we will need to |
311 | | // change this as well. |
312 | | |
313 | | template <typename T, typename Allocator> |
314 | | T* vector_as_array(vector<T, Allocator>* v) { |
315 | | #ifdef NDEBUG |
316 | | return &*v->begin(); |
317 | | #else |
318 | | return v->empty() ? NULL : &*v->begin(); |
319 | | #endif |
320 | | } |
321 | | |
322 | | template <typename T, typename Allocator> |
323 | | const T* vector_as_array(const vector<T, Allocator>* v) { |
324 | | #ifdef NDEBUG |
325 | | return &*v->begin(); |
326 | | #else |
327 | | return v->empty() ? NULL : &*v->begin(); |
328 | | #endif |
329 | | } |
330 | | |
331 | | // Return a mutable char* pointing to a string's internal buffer, |
332 | | // which may not be null-terminated. Writing through this pointer will |
333 | | // modify the string. |
334 | | // |
335 | | // string_as_array(&str)[i] is valid for 0 <= i < str.size() until the |
336 | | // next call to a string method that invalidates iterators. |
337 | | // |
338 | | // Prior to C++11, there was no standard-blessed way of getting a mutable |
339 | | // reference to a string's internal buffer. The requirement that string be |
340 | | // contiguous is officially part of the C++11 standard [string.require]/5. |
341 | | // According to Matt Austern, this should already work on all current C++98 |
342 | | // implementations. |
343 | 114k | inline char* string_as_array(string* str) { |
344 | | // DO NOT USE const_cast<char*>(str->data())! See the unittest for why. |
345 | 114k | return str->empty() ? NULL : &*str->begin(); |
346 | 114k | } |
347 | | |
348 | | // These are methods that test two hash maps/sets for equality. These exist |
349 | | // because the == operator in the STL can return false when the maps/sets |
350 | | // contain identical elements. This is because it compares the internal hash |
351 | | // tables which may be different if the order of insertions and deletions |
352 | | // differed. |
353 | | |
354 | | template <class HashSet> |
355 | | bool HashSetEquality(const HashSet& set_a, const HashSet& set_b) { |
356 | | if (set_a.size() != set_b.size()) return false; |
357 | | for (typename HashSet::const_iterator i = set_a.begin(); i != set_a.end(); ++i) |
358 | | if (set_b.find(*i) == set_b.end()) return false; |
359 | | return true; |
360 | | } |
361 | | |
362 | | template <class HashMap> |
363 | | bool HashMapEquality(const HashMap& map_a, const HashMap& map_b) { |
364 | | if (map_a.size() != map_b.size()) return false; |
365 | | for (typename HashMap::const_iterator i = map_a.begin(); i != map_a.end(); ++i) { |
366 | | typename HashMap::const_iterator j = map_b.find(i->first); |
367 | | if (j == map_b.end()) return false; |
368 | | if (i->second != j->second) return false; |
369 | | } |
370 | | return true; |
371 | | } |
372 | | |
373 | | // The following functions are useful for cleaning up STL containers |
374 | | // whose elements point to allocated memory. |
375 | | |
376 | | // STLDeleteElements() deletes all the elements in an STL container and clears |
377 | | // the container. This function is suitable for use with a vector, set, |
378 | | // hash_set, or any other STL container which defines sensible begin(), end(), |
379 | | // and clear() methods. |
380 | | // |
381 | | // If container is NULL, this function is a no-op. |
382 | | // |
383 | | // As an alternative to calling STLDeleteElements() directly, consider |
384 | | // ElementDeleter (defined below), which ensures that your container's elements |
385 | | // are deleted when the ElementDeleter goes out of scope. |
386 | | template <class T> |
387 | | void STLDeleteElements(T* container) { |
388 | | if (!container) return; |
389 | | STLDeleteContainerPointers(container->begin(), container->end()); |
390 | | container->clear(); |
391 | | } |
392 | | |
393 | | // Given an STL container consisting of (key, value) pairs, STLDeleteValues |
394 | | // deletes all the "value" components and clears the container. Does nothing |
395 | | // in the case it's given a NULL pointer. |
396 | | template <class T> |
397 | 1 | void STLDeleteValues(T* v) { |
398 | 1 | if (!v) return; |
399 | 1 | STLDeleteContainerPairSecondPointers(v->begin(), v->end()); |
400 | 1 | v->clear(); |
401 | 1 | } |
402 | | |
403 | | // ElementDeleter and ValueDeleter provide a convenient way to delete all |
404 | | // elements or values from STL containers when they go out of scope. This |
405 | | // greatly simplifies code that creates temporary objects and has multiple |
406 | | // return statements. Example: |
407 | | // |
408 | | // vector<MyProto *> tmp_proto; |
409 | | // ElementDeleter d(&tmp_proto); |
410 | | // if (...) return false; |
411 | | // ... |
412 | | // return success; |
413 | | |
414 | | // A very simple interface that simply provides a virtual destructor. It is |
415 | | // used as a non-templated base class for the TemplatedElementDeleter and |
416 | | // TemplatedValueDeleter classes. Clients should not typically use this class |
417 | | // directly. |
418 | | class BaseDeleter { |
419 | | public: |
420 | 0 | virtual ~BaseDeleter() {} |
421 | | |
422 | | protected: |
423 | 0 | BaseDeleter() {} |
424 | | |
425 | | private: |
426 | | DISALLOW_EVIL_CONSTRUCTORS(BaseDeleter); |
427 | | }; |
428 | | |
429 | | // Given a pointer to an STL container, this class will delete all the element |
430 | | // pointers when it goes out of scope. Clients should typically use |
431 | | // ElementDeleter rather than invoking this class directly. |
432 | | template <class STLContainer> |
433 | | class TemplatedElementDeleter : public BaseDeleter { |
434 | | public: |
435 | | explicit TemplatedElementDeleter(STLContainer* ptr) : container_ptr_(ptr) {} |
436 | | |
437 | | virtual ~TemplatedElementDeleter() { STLDeleteElements(container_ptr_); } |
438 | | |
439 | | private: |
440 | | STLContainer* container_ptr_ = nullptr; |
441 | | |
442 | | DISALLOW_EVIL_CONSTRUCTORS(TemplatedElementDeleter); |
443 | | }; |
444 | | |
445 | | // Like TemplatedElementDeleter, this class will delete element pointers from a |
446 | | // container when it goes out of scope. However, it is much nicer to use, |
447 | | // since the class itself is not templated. |
448 | | class ElementDeleter { |
449 | | public: |
450 | | template <class STLContainer> |
451 | | explicit ElementDeleter(STLContainer* ptr) |
452 | | : deleter_(new TemplatedElementDeleter<STLContainer>(ptr)) {} |
453 | | |
454 | 0 | ~ElementDeleter() { delete deleter_; } |
455 | | |
456 | | private: |
457 | | BaseDeleter* deleter_ = nullptr; |
458 | | |
459 | | DISALLOW_EVIL_CONSTRUCTORS(ElementDeleter); |
460 | | }; |
461 | | |
462 | | // Given a pointer to an STL container this class will delete all the value |
463 | | // pointers when it goes out of scope. Clients should typically use |
464 | | // ValueDeleter rather than invoking this class directly. |
465 | | template <class STLContainer> |
466 | | class TemplatedValueDeleter : public BaseDeleter { |
467 | | public: |
468 | | explicit TemplatedValueDeleter(STLContainer* ptr) : container_ptr_(ptr) {} |
469 | | |
470 | | virtual ~TemplatedValueDeleter() { STLDeleteValues(container_ptr_); } |
471 | | |
472 | | private: |
473 | | STLContainer* container_ptr_ = nullptr; |
474 | | |
475 | | DISALLOW_EVIL_CONSTRUCTORS(TemplatedValueDeleter); |
476 | | }; |
477 | | |
478 | | // Similar to ElementDeleter, but wraps a TemplatedValueDeleter rather than an |
479 | | // TemplatedElementDeleter. |
480 | | class ValueDeleter { |
481 | | public: |
482 | | template <class STLContainer> |
483 | | explicit ValueDeleter(STLContainer* ptr) |
484 | | : deleter_(new TemplatedValueDeleter<STLContainer>(ptr)) {} |
485 | | |
486 | 0 | ~ValueDeleter() { delete deleter_; } |
487 | | |
488 | | private: |
489 | | BaseDeleter* deleter_ = nullptr; |
490 | | |
491 | | DISALLOW_EVIL_CONSTRUCTORS(ValueDeleter); |
492 | | }; |
493 | | |
494 | | // STLElementDeleter and STLValueDeleter are similar to ElementDeleter and |
495 | | // ValueDeleter, except that: |
496 | | // - The classes are templated, making them less convenient to use. |
497 | | // - Their destructors are not virtual, making them potentially more efficient. |
498 | | // New code should typically use ElementDeleter and ValueDeleter unless |
499 | | // efficiency is a large concern. |
500 | | |
501 | | template <class STLContainer> |
502 | | class STLElementDeleter { |
503 | | public: |
504 | | STLElementDeleter(STLContainer* ptr) : container_ptr_(ptr) {} |
505 | | ~STLElementDeleter() { STLDeleteElements(container_ptr_); } |
506 | | |
507 | | private: |
508 | | STLContainer* container_ptr_ = nullptr; |
509 | | }; |
510 | | |
511 | | template <class STLContainer> |
512 | | class STLValueDeleter { |
513 | | public: |
514 | | STLValueDeleter(STLContainer* ptr) : container_ptr_(ptr) {} |
515 | | ~STLValueDeleter() { STLDeleteValues(container_ptr_); } |
516 | | |
517 | | private: |
518 | | STLContainer* container_ptr_ = nullptr; |
519 | | }; |
520 | | |
521 | | // STLSet{Difference,SymmetricDifference,Union,Intersection}(A a, B b, C *c) |
522 | | // *APPEND* the set {difference, symmetric difference, union, intersection} of |
523 | | // the two sets a and b to c. |
524 | | // STLSet{Difference,SymmetricDifference,Union,Intersection}(T a, T b) do the |
525 | | // same but return the result by value rather than by the third pointer |
526 | | // argument. The result type is the same as both of the inputs in the two |
527 | | // argument case. |
528 | | // |
529 | | // Requires: |
530 | | // a and b must be STL like containers that contain sorted data (as defined |
531 | | // by the < operator). |
532 | | // For the 3 argument version &a == c or &b == c are disallowed. In those |
533 | | // cases the 2 argument version is probably what you want anyway: |
534 | | // a = STLSetDifference(a, b); |
535 | | // |
536 | | // These function are convenience functions. The code they implement is |
537 | | // trivial (at least for now). The STL incantations they wrap are just too |
538 | | // verbose for programmers to use then and they are unpleasant to the eye. |
539 | | // Without these convenience versions people will simply keep writing one-off |
540 | | // for loops which are harder to read and more error prone. |
541 | | // |
542 | | // Note that for initial construction of an object it is just as efficient to |
543 | | // use the 2 argument version as the 3 version due to RVO (return value |
544 | | // optimization) of modern C++ compilers: |
545 | | // set<int> c = STLSetDifference(a, b); |
546 | | // is an example of where RVO comes into play. |
547 | | |
548 | | template <typename SortedSTLContainerA, typename SortedSTLContainerB, typename SortedSTLContainerC> |
549 | | void STLSetDifference(const SortedSTLContainerA& a, const SortedSTLContainerB& b, |
550 | | SortedSTLContainerC* c) { |
551 | | // The qualified name avoids an ambiguity error, particularly with C++11: |
552 | | assert(std::is_sorted(a.begin(), a.end())); |
553 | | assert(std::is_sorted(b.begin(), b.end())); |
554 | | assert(static_cast<const void*>(&a) != static_cast<const void*>(c)); |
555 | | assert(static_cast<const void*>(&b) != static_cast<const void*>(c)); |
556 | | std::set_difference(a.begin(), a.end(), b.begin(), b.end(), std::inserter(*c, c->end())); |
557 | | } |
558 | | |
559 | | template <typename SortedSTLContainer> |
560 | | SortedSTLContainer STLSetDifference(const SortedSTLContainer& a, const SortedSTLContainer& b) { |
561 | | SortedSTLContainer c; |
562 | | STLSetDifference(a, b, &c); |
563 | | return c; |
564 | | } |
565 | | |
566 | | template <typename SortedSTLContainerA, typename SortedSTLContainerB, typename SortedSTLContainerC> |
567 | | void STLSetUnion(const SortedSTLContainerA& a, const SortedSTLContainerB& b, |
568 | | SortedSTLContainerC* c) { |
569 | | assert(std::is_sorted(a.begin(), a.end())); |
570 | | assert(std::is_sorted(b.begin(), b.end())); |
571 | | assert(static_cast<const void*>(&a) != static_cast<const void*>(c)); |
572 | | assert(static_cast<const void*>(&b) != static_cast<const void*>(c)); |
573 | | std::set_union(a.begin(), a.end(), b.begin(), b.end(), std::inserter(*c, c->end())); |
574 | | } |
575 | | |
576 | | template <typename SortedSTLContainerA, typename SortedSTLContainerB, typename SortedSTLContainerC> |
577 | | void STLSetSymmetricDifference(const SortedSTLContainerA& a, const SortedSTLContainerB& b, |
578 | | SortedSTLContainerC* c) { |
579 | | assert(std::is_sorted(a.begin(), a.end())); |
580 | | assert(std::is_sorted(b.begin(), b.end())); |
581 | | assert(static_cast<const void*>(&a) != static_cast<const void*>(c)); |
582 | | assert(static_cast<const void*>(&b) != static_cast<const void*>(c)); |
583 | | std::set_symmetric_difference(a.begin(), a.end(), b.begin(), b.end(), |
584 | | std::inserter(*c, c->end())); |
585 | | } |
586 | | |
587 | | template <typename SortedSTLContainer> |
588 | | SortedSTLContainer STLSetSymmetricDifference(const SortedSTLContainer& a, |
589 | | const SortedSTLContainer& b) { |
590 | | SortedSTLContainer c; |
591 | | STLSetSymmetricDifference(a, b, &c); |
592 | | return c; |
593 | | } |
594 | | |
595 | | template <typename SortedSTLContainer> |
596 | | SortedSTLContainer STLSetUnion(const SortedSTLContainer& a, const SortedSTLContainer& b) { |
597 | | SortedSTLContainer c; |
598 | | STLSetUnion(a, b, &c); |
599 | | return c; |
600 | | } |
601 | | |
602 | | template <typename SortedSTLContainerA, typename SortedSTLContainerB, typename SortedSTLContainerC> |
603 | | void STLSetIntersection(const SortedSTLContainerA& a, const SortedSTLContainerB& b, |
604 | | SortedSTLContainerC* c) { |
605 | | assert(std::is_sorted(a.begin(), a.end())); |
606 | | assert(std::is_sorted(b.begin(), b.end())); |
607 | | assert(static_cast<const void*>(&a) != static_cast<const void*>(c)); |
608 | | assert(static_cast<const void*>(&b) != static_cast<const void*>(c)); |
609 | | std::set_intersection(a.begin(), a.end(), b.begin(), b.end(), std::inserter(*c, c->end())); |
610 | | } |
611 | | |
612 | | template <typename SortedSTLContainer> |
613 | | SortedSTLContainer STLSetIntersection(const SortedSTLContainer& a, const SortedSTLContainer& b) { |
614 | | SortedSTLContainer c; |
615 | | STLSetIntersection(a, b, &c); |
616 | | return c; |
617 | | } |
618 | | |
619 | | // Similar to STLSet{Union,Intesection,etc}, but simpler because the result is |
620 | | // always bool. |
621 | | template <typename SortedSTLContainerA, typename SortedSTLContainerB> |
622 | | bool STLIncludes(const SortedSTLContainerA& a, const SortedSTLContainerB& b) { |
623 | | assert(std::is_sorted(a.begin(), a.end())); |
624 | | assert(std::is_sorted(b.begin(), b.end())); |
625 | | return std::includes(a.begin(), a.end(), b.begin(), b.end()); |
626 | | } |
627 | | |
628 | | // Functors that compose arbitrary unary and binary functions with a |
629 | | // function that "projects" one of the members of a pair. |
630 | | // Specifically, if p1 and p2, respectively, are the functions that |
631 | | // map a pair to its first and second, respectively, members, the |
632 | | // table below summarizes the functions that can be constructed: |
633 | | // |
634 | | // * UnaryOperate1st<pair>(f) returns the function x -> f(p1(x)) |
635 | | // * UnaryOperate2nd<pair>(f) returns the function x -> f(p2(x)) |
636 | | // * BinaryOperate1st<pair>(f) returns the function (x,y) -> f(p1(x),p1(y)) |
637 | | // * BinaryOperate2nd<pair>(f) returns the function (x,y) -> f(p2(x),p2(y)) |
638 | | // |
639 | | // A typical usage for these functions would be when iterating over |
640 | | // the contents of an STL map. For other sample usage, see the unittest. |
641 | | |
642 | | template <typename Pair, typename UnaryOp> |
643 | | class UnaryOperateOnFirst { |
644 | | public: |
645 | | UnaryOperateOnFirst() {} |
646 | | |
647 | | UnaryOperateOnFirst(const UnaryOp& f) : f_(f) { // TODO(user): explicit? |
648 | | } |
649 | | |
650 | | typename UnaryOp::result_type operator()(const Pair& p) const { return f_(p.first); } |
651 | | |
652 | | private: |
653 | | UnaryOp f_; |
654 | | }; |
655 | | |
656 | | template <typename Pair, typename UnaryOp> |
657 | | UnaryOperateOnFirst<Pair, UnaryOp> UnaryOperate1st(const UnaryOp& f) { |
658 | | return UnaryOperateOnFirst<Pair, UnaryOp>(f); |
659 | | } |
660 | | |
661 | | template <typename Pair, typename UnaryOp> |
662 | | class UnaryOperateOnSecond { |
663 | | public: |
664 | | UnaryOperateOnSecond() {} |
665 | | |
666 | | UnaryOperateOnSecond(const UnaryOp& f) : f_(f) { // TODO(user): explicit? |
667 | | } |
668 | | |
669 | | typename UnaryOp::result_type operator()(const Pair& p) const { return f_(p.second); } |
670 | | |
671 | | private: |
672 | | UnaryOp f_; |
673 | | }; |
674 | | |
675 | | template <typename Pair, typename UnaryOp> |
676 | | UnaryOperateOnSecond<Pair, UnaryOp> UnaryOperate2nd(const UnaryOp& f) { |
677 | | return UnaryOperateOnSecond<Pair, UnaryOp>(f); |
678 | | } |
679 | | |
680 | | template <typename Pair, typename BinaryOp> |
681 | | class BinaryOperateOnFirst { |
682 | | public: |
683 | | BinaryOperateOnFirst() {} |
684 | | |
685 | | BinaryOperateOnFirst(const BinaryOp& f) : f_(f) { // TODO(user): explicit? |
686 | | } |
687 | | |
688 | | typename BinaryOp::result_type operator()(const Pair& p1, const Pair& p2) const { |
689 | | return f_(p1.first, p2.first); |
690 | | } |
691 | | |
692 | | private: |
693 | | BinaryOp f_; |
694 | | }; |
695 | | |
696 | | // TODO(user): explicit? |
697 | | template <typename Pair, typename BinaryOp> |
698 | | BinaryOperateOnFirst<Pair, BinaryOp> BinaryOperate1st(const BinaryOp& f) { |
699 | | return BinaryOperateOnFirst<Pair, BinaryOp>(f); |
700 | | } |
701 | | |
702 | | template <typename Pair, typename BinaryOp> |
703 | | class BinaryOperateOnSecond { |
704 | | public: |
705 | | BinaryOperateOnSecond() {} |
706 | | |
707 | | BinaryOperateOnSecond(const BinaryOp& f) : f_(f) {} |
708 | | |
709 | | typename BinaryOp::result_type operator()(const Pair& p1, const Pair& p2) const { |
710 | | return f_(p1.second, p2.second); |
711 | | } |
712 | | |
713 | | private: |
714 | | BinaryOp f_; |
715 | | }; |
716 | | |
717 | | template <typename Pair, typename BinaryOp> |
718 | | BinaryOperateOnSecond<Pair, BinaryOp> BinaryOperate2nd(const BinaryOp& f) { |
719 | | return BinaryOperateOnSecond<Pair, BinaryOp>(f); |
720 | | } |
721 | | |
722 | | // Functor that composes a binary functor h from an arbitrary binary functor |
723 | | // f and two unary functors g1, g2, so that: |
724 | | // |
725 | | // BinaryCompose1(f, g) returns function (x, y) -> f(g(x), g(y)) |
726 | | // BinaryCompose2(f, g1, g2) returns function (x, y) -> f(g1(x), g2(y)) |
727 | | // |
728 | | // This is a generalization of the BinaryOperate* functors for types other |
729 | | // than pairs. |
730 | | // |
731 | | // For sample usage, see the unittest. |
732 | | // |
733 | | // F has to be a model of AdaptableBinaryFunction. |
734 | | // G1 and G2 have to be models of AdabtableUnaryFunction. |
735 | | template <typename F, typename G1, typename G2> |
736 | | class BinaryComposeBinary { |
737 | | public: |
738 | | BinaryComposeBinary(F f, G1 g1, G2 g2) : f_(f), g1_(g1), g2_(g2) {} |
739 | | |
740 | | typename F::result_type operator()(typename G1::argument_type x, |
741 | | typename G2::argument_type y) const { |
742 | | return f_(g1_(x), g2_(y)); |
743 | | } |
744 | | |
745 | | private: |
746 | | F f_; |
747 | | G1 g1_; |
748 | | G2 g2_; |
749 | | }; |
750 | | |
751 | | template <typename F, typename G> |
752 | | BinaryComposeBinary<F, G, G> BinaryCompose1(F f, G g) { |
753 | | return BinaryComposeBinary<F, G, G>(f, g, g); |
754 | | } |
755 | | |
756 | | template <typename F, typename G1, typename G2> |
757 | | BinaryComposeBinary<F, G1, G2> BinaryCompose2(F f, G1 g1, G2 g2) { |
758 | | return BinaryComposeBinary<F, G1, G2>(f, g1, g2); |
759 | | } |
760 | | |
761 | | // Even though a struct has no data members, it cannot have zero size |
762 | | // according to the standard. However, "empty base-class |
763 | | // optimization" allows an empty parent class to add no additional |
764 | | // size to the object. STLEmptyBaseHandle is a handy way to "stuff" |
765 | | // objects that are typically empty (e.g., allocators, compare |
766 | | // objects) into other fields of an object without increasing the size |
767 | | // of the object. |
768 | | // |
769 | | // struct Empty { |
770 | | // void Method() { } |
771 | | // }; |
772 | | // struct OneInt { |
773 | | // STLEmptyBaseHandle<Empty, int> i; |
774 | | // }; |
775 | | // |
776 | | // In the example above, "i.data" refers to the integer field, whereas |
777 | | // "i" refers to the empty base class. sizeof(OneInt) == sizeof(int) |
778 | | // despite the fact that sizeof(Empty) > 0. |
779 | | template <typename Base, typename Data> |
780 | | struct STLEmptyBaseHandle : public Base { |
781 | | template <typename U> |
782 | | STLEmptyBaseHandle(const U& b, const Data& d) : Base(b), data(d) {} |
783 | | Data data; |
784 | | }; |
785 | | |
786 | | // These functions return true if there is some element in the sorted range |
787 | | // [begin1, end) which is equal to some element in the sorted range [begin2, |
788 | | // end2). The iterators do not have to be of the same type, but the value types |
789 | | // must be less-than comparable. (Two elements a,b are considered equal if |
790 | | // !(a < b) && !(b < a). |
791 | | template <typename InputIterator1, typename InputIterator2> |
792 | | bool SortedRangesHaveIntersection(InputIterator1 begin1, InputIterator1 end1, InputIterator2 begin2, |
793 | | InputIterator2 end2) { |
794 | | assert(std::is_sorted(begin1, end1)); |
795 | | assert(std::is_sorted(begin2, end2)); |
796 | | while (begin1 != end1 && begin2 != end2) { |
797 | | if (*begin1 < *begin2) { |
798 | | ++begin1; |
799 | | } else if (*begin2 < *begin1) { |
800 | | ++begin2; |
801 | | } else { |
802 | | return true; |
803 | | } |
804 | | } |
805 | | return false; |
806 | | } |
807 | | |
808 | | // This is equivalent to the function above, but using a custom comparison |
809 | | // function. |
810 | | template <typename InputIterator1, typename InputIterator2, typename Comp> |
811 | | bool SortedRangesHaveIntersection(InputIterator1 begin1, InputIterator1 end1, InputIterator2 begin2, |
812 | | InputIterator2 end2, Comp comparator) { |
813 | | assert(std::is_sorted(begin1, end1, comparator)); |
814 | | assert(std::is_sorted(begin2, end2, comparator)); |
815 | | while (begin1 != end1 && begin2 != end2) { |
816 | | if (comparator(*begin1, *begin2)) { |
817 | | ++begin1; |
818 | | } else if (comparator(*begin2, *begin1)) { |
819 | | ++begin2; |
820 | | } else { |
821 | | return true; |
822 | | } |
823 | | } |
824 | | return false; |
825 | | } |
826 | | |
827 | | // release_ptr is intended to help remove systematic use of gscoped_ptr |
828 | | // in cases like: |
829 | | // |
830 | | // vector<Foo *> v; |
831 | | // ElementDeleter d(&v); |
832 | | // ... { |
833 | | // int remove_idx = f(v); |
834 | | // gscoped_ptr<Foo> t(v[remove_idx]); |
835 | | // v[remove_idx] = NULL; // Save from deleter. |
836 | | // return t.release(); |
837 | | // } |
838 | | // |
839 | | // This would be replaced by: |
840 | | // ... { |
841 | | // int remove_idx = f(v); |
842 | | // return release_ptr(&v[remove_idx]); |
843 | | // } |
844 | | template <typename T> |
845 | | T* release_ptr(T** ptr) MUST_USE_RESULT; |
846 | | template <typename T> |
847 | | T* release_ptr(T** ptr) { |
848 | | assert(ptr); |
849 | | T* tmp = *ptr; |
850 | | *ptr = NULL; |
851 | | return tmp; |
852 | | } |