OLD | NEW |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef BASE_CONTAINERS_FLAT_TREE_H_ | 5 #ifndef BASE_CONTAINERS_FLAT_TREE_H_ |
6 #define BASE_CONTAINERS_FLAT_TREE_H_ | 6 #define BASE_CONTAINERS_FLAT_TREE_H_ |
7 | 7 |
8 #include <algorithm> | 8 #include <algorithm> |
| 9 #include <iterator> |
9 #include <vector> | 10 #include <vector> |
10 | 11 |
11 namespace base { | 12 namespace base { |
12 | 13 |
13 enum FlatContainerDupes { | 14 enum FlatContainerDupes { |
14 KEEP_FIRST_OF_DUPES, | 15 KEEP_FIRST_OF_DUPES, |
15 KEEP_LAST_OF_DUPES, | 16 KEEP_LAST_OF_DUPES, |
16 }; | 17 }; |
17 | 18 |
18 namespace internal { | 19 namespace internal { |
19 | 20 |
| 21 // This is a convenience method returning true if Iterator is at least a |
| 22 // ForwardIterator and thus supports multiple passes over a range. |
| 23 template <class Iterator> |
| 24 constexpr bool is_multipass() { |
| 25 return std::is_base_of< |
| 26 std::forward_iterator_tag, |
| 27 typename std::iterator_traits<Iterator>::iterator_category>::value; |
| 28 } |
| 29 |
20 // This algorithm is like unique() from the standard library except it | 30 // This algorithm is like unique() from the standard library except it |
21 // selects only the last of consecutive values instead of the first. | 31 // selects only the last of consecutive values instead of the first. |
22 template <class Iterator, class BinaryPredicate> | 32 template <class Iterator, class BinaryPredicate> |
23 Iterator LastUnique(Iterator first, Iterator last, BinaryPredicate compare) { | 33 Iterator LastUnique(Iterator first, Iterator last, BinaryPredicate compare) { |
24 Iterator replacable = std::adjacent_find(first, last, compare); | 34 Iterator replacable = std::adjacent_find(first, last, compare); |
25 | 35 |
26 // No duplicate elements found. | 36 // No duplicate elements found. |
27 if (replacable == last) | 37 if (replacable == last) |
28 return last; | 38 return last; |
29 | 39 |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
180 const_reverse_iterator crbegin() const; | 190 const_reverse_iterator crbegin() const; |
181 | 191 |
182 reverse_iterator rend(); | 192 reverse_iterator rend(); |
183 const_reverse_iterator rend() const; | 193 const_reverse_iterator rend() const; |
184 const_reverse_iterator crend() const; | 194 const_reverse_iterator crend() const; |
185 | 195 |
186 // -------------------------------------------------------------------------- | 196 // -------------------------------------------------------------------------- |
187 // Insert operations. | 197 // Insert operations. |
188 // | 198 // |
189 // Assume that every operation invalidates iterators and references. | 199 // Assume that every operation invalidates iterators and references. |
190 // Insertion of one element can take O(size). See the Notes section in the | 200 // Insertion of one element can take O(size). Capacity of flat_tree grows in |
191 // class comments on why we do not currently implement range insertion. | 201 // an implementation-defined manner. |
192 // Capacity of flat_tree grows in an implementation-defined manner. | |
193 // | 202 // |
194 // NOTE: Prefer to build a new flat_tree from a std::vector (or similar) | 203 // NOTE: Prefer to build a new flat_tree from a std::vector (or similar) |
195 // instead of calling insert() repeatedly. | 204 // instead of calling insert() repeatedly. |
196 | 205 |
197 std::pair<iterator, bool> insert(const value_type& val); | 206 std::pair<iterator, bool> insert(const value_type& val); |
198 std::pair<iterator, bool> insert(value_type&& val); | 207 std::pair<iterator, bool> insert(value_type&& val); |
199 | 208 |
200 iterator insert(const_iterator position_hint, const value_type& x); | 209 iterator insert(const_iterator position_hint, const value_type& x); |
201 iterator insert(const_iterator position_hint, value_type&& x); | 210 iterator insert(const_iterator position_hint, value_type&& x); |
202 | 211 |
| 212 // This method inserts the values from the range [first, last) into the |
| 213 // current tree. In case of KEEP_LAST_OF_DUPES newly added elements can |
| 214 // overwrite existing values. |
| 215 template <class InputIterator> |
| 216 void insert(InputIterator first, |
| 217 InputIterator last, |
| 218 FlatContainerDupes dupes); |
| 219 |
203 template <class... Args> | 220 template <class... Args> |
204 std::pair<iterator, bool> emplace(Args&&... args); | 221 std::pair<iterator, bool> emplace(Args&&... args); |
205 | 222 |
206 template <class... Args> | 223 template <class... Args> |
207 iterator emplace_hint(const_iterator position_hint, Args&&... args); | 224 iterator emplace_hint(const_iterator position_hint, Args&&... args); |
208 | 225 |
209 // -------------------------------------------------------------------------- | 226 // -------------------------------------------------------------------------- |
210 // Erase operations. | 227 // Erase operations. |
211 // | 228 // |
212 // Assume that every operation invalidates iterators and references. | 229 // Assume that every operation invalidates iterators and references. |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
309 const key_compare& key_comp_; | 326 const key_compare& key_comp_; |
310 }; | 327 }; |
311 | 328 |
312 const flat_tree& as_const() { return *this; } | 329 const flat_tree& as_const() { return *this; } |
313 | 330 |
314 iterator const_cast_it(const_iterator c_it) { | 331 iterator const_cast_it(const_iterator c_it) { |
315 auto distance = std::distance(cbegin(), c_it); | 332 auto distance = std::distance(cbegin(), c_it); |
316 return std::next(begin(), distance); | 333 return std::next(begin(), distance); |
317 } | 334 } |
318 | 335 |
319 void sort_and_unique(FlatContainerDupes dupes) { | 336 // This method is inspired by both std::map::insert(P&&) and |
| 337 // std::map::insert_or_assign(const K&, V&&). It inserts val if an equivalent |
| 338 // element is not present yet, otherwise it overwrites. It returns an iterator |
| 339 // to the modified element and a flag indicating whether insertion or |
| 340 // assignment happened. |
| 341 template <class V> |
| 342 std::pair<iterator, bool> insert_or_assign(V&& val) { |
| 343 auto position = lower_bound(GetKeyFromValue()(val)); |
| 344 |
| 345 if (position == end() || value_comp()(val, *position)) |
| 346 return {impl_.body_.emplace(position, std::forward<V>(val)), true}; |
| 347 |
| 348 *position = std::forward<V>(val); |
| 349 return {position, false}; |
| 350 } |
| 351 |
| 352 // This method is similar to insert_or_assign, with the following differences: |
| 353 // - Instead of searching [begin(), end()) it only searches [first, last). |
| 354 // - In case no equivalent element is found, val is appended to the end of the |
| 355 // underlying body and an iterator to the next bigger element in [first, |
| 356 // last) is returned. |
| 357 template <class V> |
| 358 std::pair<iterator, bool> append_or_assign(iterator first, |
| 359 iterator last, |
| 360 V&& val) { |
| 361 auto position = std::lower_bound(first, last, val, value_comp()); |
| 362 |
| 363 if (position == last || value_comp()(val, *position)) { |
| 364 // emplace_back might invalidate position, which is why distance needs to |
| 365 // be cached. |
| 366 const difference_type distance = std::distance(begin(), position); |
| 367 impl_.body_.emplace_back(std::forward<V>(val)); |
| 368 return {std::next(begin(), distance), true}; |
| 369 } |
| 370 |
| 371 *position = std::forward<V>(val); |
| 372 return {position, false}; |
| 373 } |
| 374 |
| 375 // This method is similar to insert, with the following differences: |
| 376 // - Instead of searching [begin(), end()) it only searches [first, last). |
| 377 // - In case no equivalent element is found, val is appended to the end of the |
| 378 // underlying body and an iterator to the next bigger element in [first, |
| 379 // last) is returned. |
| 380 template <class V> |
| 381 std::pair<iterator, bool> append_unique(iterator first, |
| 382 iterator last, |
| 383 V&& val) { |
| 384 auto position = std::lower_bound(first, last, val, value_comp()); |
| 385 |
| 386 if (position == last || value_comp()(val, *position)) { |
| 387 // emplace_back might invalidate position, which is why distance needs to |
| 388 // be cached. |
| 389 const difference_type distance = std::distance(begin(), position); |
| 390 impl_.body_.emplace_back(std::forward<V>(val)); |
| 391 return {std::next(begin(), distance), true}; |
| 392 } |
| 393 |
| 394 return {position, false}; |
| 395 } |
| 396 |
| 397 void sort_and_unique(iterator first, |
| 398 iterator last, |
| 399 FlatContainerDupes dupes) { |
320 // Preserve stability for the unique code below. | 400 // Preserve stability for the unique code below. |
321 std::stable_sort(begin(), end(), impl_.get_value_comp()); | 401 std::stable_sort(first, last, impl_.get_value_comp()); |
322 | 402 |
323 auto comparator = [this](const value_type& lhs, const value_type& rhs) { | 403 auto comparator = [this](const value_type& lhs, const value_type& rhs) { |
324 // lhs is already <= rhs due to sort, therefore | 404 // lhs is already <= rhs due to sort, therefore |
325 // !(lhs < rhs) <=> lhs == rhs. | 405 // !(lhs < rhs) <=> lhs == rhs. |
326 return !impl_.get_value_comp()(lhs, rhs); | 406 return !impl_.get_value_comp()(lhs, rhs); |
327 }; | 407 }; |
328 | 408 |
329 iterator erase_after; | 409 iterator erase_after; |
330 switch (dupes) { | 410 switch (dupes) { |
331 case KEEP_FIRST_OF_DUPES: | 411 case KEEP_FIRST_OF_DUPES: |
332 erase_after = std::unique(begin(), end(), comparator); | 412 erase_after = std::unique(first, last, comparator); |
333 break; | 413 break; |
334 case KEEP_LAST_OF_DUPES: | 414 case KEEP_LAST_OF_DUPES: |
335 erase_after = LastUnique(begin(), end(), comparator); | 415 erase_after = LastUnique(first, last, comparator); |
336 break; | 416 break; |
337 } | 417 } |
338 erase(erase_after, end()); | 418 erase(erase_after, last); |
339 } | 419 } |
340 | 420 |
341 // To support comparators that may not be possible to default-construct, we | 421 // To support comparators that may not be possible to default-construct, we |
342 // have to store an instance of Compare. Using this to store all internal | 422 // have to store an instance of Compare. Using this to store all internal |
343 // state of flat_tree and using private inheritance to store compare lets us | 423 // state of flat_tree and using private inheritance to store compare lets us |
344 // take advantage of an empty base class optimization to avoid extra space in | 424 // take advantage of an empty base class optimization to avoid extra space in |
345 // the common case when Compare has no state. | 425 // the common case when Compare has no state. |
346 struct Impl : private value_compare { | 426 struct Impl : private value_compare { |
347 Impl() = default; | 427 Impl() = default; |
348 | 428 |
(...skipping 21 matching lines...) Expand all Loading... |
370 : impl_(comp) {} | 450 : impl_(comp) {} |
371 | 451 |
372 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 452 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
373 template <class InputIterator> | 453 template <class InputIterator> |
374 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( | 454 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( |
375 InputIterator first, | 455 InputIterator first, |
376 InputIterator last, | 456 InputIterator last, |
377 FlatContainerDupes dupe_handling, | 457 FlatContainerDupes dupe_handling, |
378 const KeyCompare& comp) | 458 const KeyCompare& comp) |
379 : impl_(comp, first, last) { | 459 : impl_(comp, first, last) { |
380 sort_and_unique(dupe_handling); | 460 sort_and_unique(begin(), end(), dupe_handling); |
381 } | 461 } |
382 | 462 |
383 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 463 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
384 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( | 464 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( |
385 const flat_tree&) = default; | 465 const flat_tree&) = default; |
386 | 466 |
387 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 467 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
388 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(flat_tree&&) = | 468 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(flat_tree&&) = |
389 default; | 469 default; |
390 | 470 |
391 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 471 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
392 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( | 472 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( |
393 std::vector<value_type> items, | 473 std::vector<value_type> items, |
394 FlatContainerDupes dupe_handling, | 474 FlatContainerDupes dupe_handling, |
395 const KeyCompare& comp) | 475 const KeyCompare& comp) |
396 : impl_(comp, std::move(items)) { | 476 : impl_(comp, std::move(items)) { |
397 sort_and_unique(dupe_handling); | 477 sort_and_unique(begin(), end(), dupe_handling); |
398 } | 478 } |
399 | 479 |
400 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 480 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
401 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( | 481 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( |
402 std::initializer_list<value_type> ilist, | 482 std::initializer_list<value_type> ilist, |
403 FlatContainerDupes dupe_handling, | 483 FlatContainerDupes dupe_handling, |
404 const KeyCompare& comp) | 484 const KeyCompare& comp) |
405 : flat_tree(std::begin(ilist), std::end(ilist), dupe_handling, comp) {} | 485 : flat_tree(std::begin(ilist), std::end(ilist), dupe_handling, comp) {} |
406 | 486 |
407 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 487 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
408 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::~flat_tree() = default; | 488 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::~flat_tree() = default; |
409 | 489 |
410 // ---------------------------------------------------------------------------- | 490 // ---------------------------------------------------------------------------- |
411 // Assignments. | 491 // Assignments. |
412 | 492 |
413 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 493 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
414 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=( | 494 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=( |
415 const flat_tree&) -> flat_tree& = default; | 495 const flat_tree&) -> flat_tree& = default; |
416 | 496 |
417 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 497 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
418 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=(flat_tree &&) | 498 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=(flat_tree &&) |
419 -> flat_tree& = default; | 499 -> flat_tree& = default; |
420 | 500 |
421 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 501 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
422 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=( | 502 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=( |
423 std::initializer_list<value_type> ilist) -> flat_tree& { | 503 std::initializer_list<value_type> ilist) -> flat_tree& { |
424 impl_.body_ = ilist; | 504 impl_.body_ = ilist; |
425 sort_and_unique(KEEP_FIRST_OF_DUPES); | 505 sort_and_unique(begin(), end(), KEEP_FIRST_OF_DUPES); |
426 return *this; | 506 return *this; |
427 } | 507 } |
428 | 508 |
429 // ---------------------------------------------------------------------------- | 509 // ---------------------------------------------------------------------------- |
430 // Memory management. | 510 // Memory management. |
431 | 511 |
432 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 512 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
433 void flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::reserve( | 513 void flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::reserve( |
434 size_type new_capacity) { | 514 size_type new_capacity) { |
435 impl_.body_.reserve(new_capacity); | 515 impl_.body_.reserve(new_capacity); |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
549 // | 629 // |
550 // Currently we use position_hint the same way as eastl or boost: | 630 // Currently we use position_hint the same way as eastl or boost: |
551 // https://github.com/electronicarts/EASTL/blob/master/include/EASTL/vector_set.
h#L493 | 631 // https://github.com/electronicarts/EASTL/blob/master/include/EASTL/vector_set.
h#L493 |
552 // | 632 // |
553 // We duplicate code between copy and move version so that we can avoid | 633 // We duplicate code between copy and move version so that we can avoid |
554 // creating a temporary value. | 634 // creating a temporary value. |
555 | 635 |
556 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 636 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
557 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::insert( | 637 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::insert( |
558 const value_type& val) -> std::pair<iterator, bool> { | 638 const value_type& val) -> std::pair<iterator, bool> { |
559 auto position = lower_bound(val); | 639 GetKeyFromValue extractor; |
| 640 auto position = lower_bound(extractor(val)); |
560 | 641 |
561 if (position == end() || impl_.get_value_comp()(val, *position)) | 642 if (position == end() || impl_.get_value_comp()(val, *position)) |
562 return {impl_.body_.insert(position, val), true}; | 643 return {impl_.body_.insert(position, val), true}; |
563 | 644 |
564 return {position, false}; | 645 return {position, false}; |
565 } | 646 } |
566 | 647 |
567 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 648 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
568 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::insert( | 649 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::insert( |
569 value_type&& val) -> std::pair<iterator, bool> { | 650 value_type&& val) -> std::pair<iterator, bool> { |
(...skipping 26 matching lines...) Expand all Loading... |
596 if (position_hint == end() || impl_.get_value_comp()(val, *position_hint)) { | 677 if (position_hint == end() || impl_.get_value_comp()(val, *position_hint)) { |
597 if (position_hint == begin() || | 678 if (position_hint == begin() || |
598 impl_.get_value_comp()(*(position_hint - 1), val)) | 679 impl_.get_value_comp()(*(position_hint - 1), val)) |
599 // We have to cast away const because of crbug.com/677044. | 680 // We have to cast away const because of crbug.com/677044. |
600 return impl_.body_.insert(const_cast_it(position_hint), std::move(val)); | 681 return impl_.body_.insert(const_cast_it(position_hint), std::move(val)); |
601 } | 682 } |
602 return insert(std::move(val)).first; | 683 return insert(std::move(val)).first; |
603 } | 684 } |
604 | 685 |
605 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 686 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
| 687 template <class InputIterator> |
| 688 void flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::insert( |
| 689 InputIterator first, |
| 690 InputIterator last, |
| 691 FlatContainerDupes dupes) { |
| 692 if (first == last) |
| 693 return; |
| 694 |
| 695 // Cache results whether existing elements should be overwritten and whether |
| 696 // inserting new elements happens immediately or will be done in a batch. |
| 697 const bool overwrite_existing = dupes == KEEP_LAST_OF_DUPES; |
| 698 const bool insert_inplace = |
| 699 is_multipass<InputIterator>() && std::next(first) == last; |
| 700 |
| 701 if (insert_inplace) { |
| 702 if (overwrite_existing) { |
| 703 for (; first != last; ++first) |
| 704 insert_or_assign(*first); |
| 705 } else |
| 706 std::copy(first, last, std::inserter(*this, end())); |
| 707 return; |
| 708 } |
| 709 |
| 710 // Provide a convenience lambda to obtain an iterator pointing past the last |
| 711 // old element. This needs to be dymanic due to possible re-allocations. |
| 712 const size_type original_size = size(); |
| 713 auto middle = [this, original_size]() { |
| 714 return std::next(begin(), original_size); |
| 715 }; |
| 716 |
| 717 // For batch updates initialize the first insertion point. |
| 718 difference_type pos_first_new = original_size; |
| 719 |
| 720 // Loop over the input range while appending new values and overwriting |
| 721 // existing ones, if applicable. Keep track of the first insertion point. |
| 722 if (overwrite_existing) { |
| 723 for (; first != last; ++first) { |
| 724 std::pair<iterator, bool> result = |
| 725 append_or_assign(begin(), middle(), *first); |
| 726 if (result.second) { |
| 727 pos_first_new = |
| 728 std::min(pos_first_new, std::distance(begin(), result.first)); |
| 729 } |
| 730 } |
| 731 } else { |
| 732 for (; first != last; ++first) { |
| 733 std::pair<iterator, bool> result = |
| 734 append_unique(begin(), middle(), *first); |
| 735 if (result.second) { |
| 736 pos_first_new = |
| 737 std::min(pos_first_new, std::distance(begin(), result.first)); |
| 738 } |
| 739 } |
| 740 } |
| 741 |
| 742 // The new elements might be unordered and contain duplicates, so post-process |
| 743 // the just inserted elements and merge them with the rest, inserting them at |
| 744 // the previously found spot. |
| 745 sort_and_unique(middle(), end(), dupes); |
| 746 std::inplace_merge(std::next(begin(), pos_first_new), middle(), end(), |
| 747 value_comp()); |
| 748 } |
| 749 |
| 750 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
606 template <class... Args> | 751 template <class... Args> |
607 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::emplace(Args&&... args) | 752 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::emplace(Args&&... args) |
608 -> std::pair<iterator, bool> { | 753 -> std::pair<iterator, bool> { |
609 return insert(value_type(std::forward<Args>(args)...)); | 754 return insert(value_type(std::forward<Args>(args)...)); |
610 } | 755 } |
611 | 756 |
612 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 757 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
613 template <class... Args> | 758 template <class... Args> |
614 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::emplace_hint( | 759 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::emplace_hint( |
615 const_iterator position_hint, | 760 const_iterator position_hint, |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
768 void EraseIf(base::internal::flat_tree<Key, Value, GetKeyFromValue, KeyCompare>& | 913 void EraseIf(base::internal::flat_tree<Key, Value, GetKeyFromValue, KeyCompare>& |
769 container, | 914 container, |
770 Predicate pred) { | 915 Predicate pred) { |
771 container.erase(std::remove_if(container.begin(), container.end(), pred), | 916 container.erase(std::remove_if(container.begin(), container.end(), pred), |
772 container.end()); | 917 container.end()); |
773 } | 918 } |
774 | 919 |
775 } // namespace base | 920 } // namespace base |
776 | 921 |
777 #endif // BASE_CONTAINERS_FLAT_TREE_H_ | 922 #endif // BASE_CONTAINERS_FLAT_TREE_H_ |
OLD | NEW |