Chromium Code Reviews| 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. | |
| 356 template <class V> | |
| 357 std::pair<iterator, bool> append_or_assign(iterator first, | |
|
dyaroshev
2017/05/17 10:15:19
I don't actually believe, that in these methods re
jdoerrie
2017/05/17 11:32:05
Done.
| |
| 358 iterator last, | |
| 359 V&& val) { | |
| 360 auto position = std::lower_bound(first, last, val, value_comp()); | |
| 361 | |
| 362 if (position == last || value_comp()(val, *position)) { | |
| 363 impl_.body_.emplace_back(std::forward<V>(val)); | |
| 364 return {std::prev(end()), true}; | |
| 365 } | |
| 366 | |
| 367 *position = std::forward<V>(val); | |
| 368 return {position, false}; | |
| 369 } | |
| 370 | |
| 371 // This method is similar to insert, with the following differences: | |
| 372 // - Instead of searching [begin(), end()) it only searches [first, last). | |
| 373 // - In case no equivalent element is found, val is appended to the end of the | |
| 374 // underlying body. | |
| 375 template <class V> | |
| 376 std::pair<iterator, bool> append_unique(iterator first, | |
| 377 iterator last, | |
| 378 V&& val) { | |
| 379 auto position = std::lower_bound(first, last, val, value_comp()); | |
| 380 | |
| 381 if (position == last || value_comp()(val, *position)) { | |
| 382 impl_.body_.emplace_back(std::forward<V>(val)); | |
| 383 return {std::prev(end()), true}; | |
| 384 } | |
| 385 | |
| 386 return {position, false}; | |
| 387 } | |
| 388 | |
| 389 void sort_and_unique(iterator first, | |
| 390 iterator last, | |
| 391 FlatContainerDupes dupes) { | |
| 320 // Preserve stability for the unique code below. | 392 // Preserve stability for the unique code below. |
| 321 std::stable_sort(begin(), end(), impl_.get_value_comp()); | 393 std::stable_sort(first, last, impl_.get_value_comp()); |
| 322 | 394 |
| 323 auto comparator = [this](const value_type& lhs, const value_type& rhs) { | 395 auto comparator = [this](const value_type& lhs, const value_type& rhs) { |
| 324 // lhs is already <= rhs due to sort, therefore | 396 // lhs is already <= rhs due to sort, therefore |
| 325 // !(lhs < rhs) <=> lhs == rhs. | 397 // !(lhs < rhs) <=> lhs == rhs. |
| 326 return !impl_.get_value_comp()(lhs, rhs); | 398 return !impl_.get_value_comp()(lhs, rhs); |
| 327 }; | 399 }; |
| 328 | 400 |
| 329 iterator erase_after; | 401 iterator erase_after; |
| 330 switch (dupes) { | 402 switch (dupes) { |
| 331 case KEEP_FIRST_OF_DUPES: | 403 case KEEP_FIRST_OF_DUPES: |
| 332 erase_after = std::unique(begin(), end(), comparator); | 404 erase_after = std::unique(first, last, comparator); |
| 333 break; | 405 break; |
| 334 case KEEP_LAST_OF_DUPES: | 406 case KEEP_LAST_OF_DUPES: |
| 335 erase_after = LastUnique(begin(), end(), comparator); | 407 erase_after = LastUnique(first, last, comparator); |
| 336 break; | 408 break; |
| 337 } | 409 } |
| 338 erase(erase_after, end()); | 410 erase(erase_after, last); |
| 339 } | 411 } |
| 340 | 412 |
| 341 // To support comparators that may not be possible to default-construct, we | 413 // 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 | 414 // 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 | 415 // 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 | 416 // take advantage of an empty base class optimization to avoid extra space in |
| 345 // the common case when Compare has no state. | 417 // the common case when Compare has no state. |
| 346 struct Impl : private value_compare { | 418 struct Impl : private value_compare { |
| 347 Impl() = default; | 419 Impl() = default; |
| 348 | 420 |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 370 : impl_(comp) {} | 442 : impl_(comp) {} |
| 371 | 443 |
| 372 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 444 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
| 373 template <class InputIterator> | 445 template <class InputIterator> |
| 374 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( | 446 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( |
| 375 InputIterator first, | 447 InputIterator first, |
| 376 InputIterator last, | 448 InputIterator last, |
| 377 FlatContainerDupes dupe_handling, | 449 FlatContainerDupes dupe_handling, |
| 378 const KeyCompare& comp) | 450 const KeyCompare& comp) |
| 379 : impl_(comp, first, last) { | 451 : impl_(comp, first, last) { |
| 380 sort_and_unique(dupe_handling); | 452 sort_and_unique(begin(), end(), dupe_handling); |
| 381 } | 453 } |
| 382 | 454 |
| 383 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 455 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
| 384 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( | 456 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( |
| 385 const flat_tree&) = default; | 457 const flat_tree&) = default; |
| 386 | 458 |
| 387 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 459 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
| 388 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(flat_tree&&) = | 460 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(flat_tree&&) = |
| 389 default; | 461 default; |
| 390 | 462 |
| 391 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 463 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
| 392 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( | 464 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( |
| 393 std::vector<value_type> items, | 465 std::vector<value_type> items, |
| 394 FlatContainerDupes dupe_handling, | 466 FlatContainerDupes dupe_handling, |
| 395 const KeyCompare& comp) | 467 const KeyCompare& comp) |
| 396 : impl_(comp, std::move(items)) { | 468 : impl_(comp, std::move(items)) { |
| 397 sort_and_unique(dupe_handling); | 469 sort_and_unique(begin(), end(), dupe_handling); |
| 398 } | 470 } |
| 399 | 471 |
| 400 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 472 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
| 401 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( | 473 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( |
| 402 std::initializer_list<value_type> ilist, | 474 std::initializer_list<value_type> ilist, |
| 403 FlatContainerDupes dupe_handling, | 475 FlatContainerDupes dupe_handling, |
| 404 const KeyCompare& comp) | 476 const KeyCompare& comp) |
| 405 : flat_tree(std::begin(ilist), std::end(ilist), dupe_handling, comp) {} | 477 : flat_tree(std::begin(ilist), std::end(ilist), dupe_handling, comp) {} |
| 406 | 478 |
| 407 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 479 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
| 408 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::~flat_tree() = default; | 480 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::~flat_tree() = default; |
| 409 | 481 |
| 410 // ---------------------------------------------------------------------------- | 482 // ---------------------------------------------------------------------------- |
| 411 // Assignments. | 483 // Assignments. |
| 412 | 484 |
| 413 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 485 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
| 414 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=( | 486 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=( |
| 415 const flat_tree&) -> flat_tree& = default; | 487 const flat_tree&) -> flat_tree& = default; |
| 416 | 488 |
| 417 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 489 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
| 418 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=(flat_tree &&) | 490 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=(flat_tree &&) |
| 419 -> flat_tree& = default; | 491 -> flat_tree& = default; |
| 420 | 492 |
| 421 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 493 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
| 422 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=( | 494 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=( |
| 423 std::initializer_list<value_type> ilist) -> flat_tree& { | 495 std::initializer_list<value_type> ilist) -> flat_tree& { |
| 424 impl_.body_ = ilist; | 496 impl_.body_ = ilist; |
| 425 sort_and_unique(KEEP_FIRST_OF_DUPES); | 497 sort_and_unique(begin(), end(), KEEP_FIRST_OF_DUPES); |
| 426 return *this; | 498 return *this; |
| 427 } | 499 } |
| 428 | 500 |
| 429 // ---------------------------------------------------------------------------- | 501 // ---------------------------------------------------------------------------- |
| 430 // Memory management. | 502 // Memory management. |
| 431 | 503 |
| 432 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 504 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
| 433 void flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::reserve( | 505 void flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::reserve( |
| 434 size_type new_capacity) { | 506 size_type new_capacity) { |
| 435 impl_.body_.reserve(new_capacity); | 507 impl_.body_.reserve(new_capacity); |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 549 // | 621 // |
| 550 // Currently we use position_hint the same way as eastl or boost: | 622 // 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 | 623 // https://github.com/electronicarts/EASTL/blob/master/include/EASTL/vector_set. h#L493 |
| 552 // | 624 // |
| 553 // We duplicate code between copy and move version so that we can avoid | 625 // We duplicate code between copy and move version so that we can avoid |
| 554 // creating a temporary value. | 626 // creating a temporary value. |
| 555 | 627 |
| 556 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 628 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
| 557 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::insert( | 629 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::insert( |
| 558 const value_type& val) -> std::pair<iterator, bool> { | 630 const value_type& val) -> std::pair<iterator, bool> { |
| 559 auto position = lower_bound(val); | 631 GetKeyFromValue extractor; |
| 632 auto position = lower_bound(extractor(val)); | |
| 560 | 633 |
| 561 if (position == end() || impl_.get_value_comp()(val, *position)) | 634 if (position == end() || impl_.get_value_comp()(val, *position)) |
| 562 return {impl_.body_.insert(position, val), true}; | 635 return {impl_.body_.insert(position, val), true}; |
| 563 | 636 |
| 564 return {position, false}; | 637 return {position, false}; |
| 565 } | 638 } |
| 566 | 639 |
| 567 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 640 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
| 568 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::insert( | 641 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::insert( |
| 569 value_type&& val) -> std::pair<iterator, bool> { | 642 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)) { | 669 if (position_hint == end() || impl_.get_value_comp()(val, *position_hint)) { |
| 597 if (position_hint == begin() || | 670 if (position_hint == begin() || |
| 598 impl_.get_value_comp()(*(position_hint - 1), val)) | 671 impl_.get_value_comp()(*(position_hint - 1), val)) |
| 599 // We have to cast away const because of crbug.com/677044. | 672 // We have to cast away const because of crbug.com/677044. |
| 600 return impl_.body_.insert(const_cast_it(position_hint), std::move(val)); | 673 return impl_.body_.insert(const_cast_it(position_hint), std::move(val)); |
| 601 } | 674 } |
| 602 return insert(std::move(val)).first; | 675 return insert(std::move(val)).first; |
| 603 } | 676 } |
| 604 | 677 |
| 605 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 678 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
| 679 template <class InputIterator> | |
| 680 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::insert( | |
| 681 InputIterator first, | |
| 682 InputIterator last, | |
| 683 FlatContainerDupes dupes) -> void { | |
|
dyaroshev
2017/05/17 10:15:19
Nit: we just wrote void, cause the type doesn't de
jdoerrie
2017/05/17 11:32:05
Done.
| |
| 684 if (first == last) | |
| 685 return; | |
| 686 | |
| 687 // Cache results whether existing elements should be overwritten and whether | |
| 688 // inserting new elements happens immediately or will be done in a batch. | |
| 689 const bool overwrite_existing = dupes == KEEP_LAST_OF_DUPES; | |
| 690 const bool insert_inplace = | |
| 691 is_multipass<InputIterator>() && std::next(first) == last; | |
|
jdoerrie
2017/05/17 06:41:16
You were right with your earlier comment that this
dyaroshev
2017/05/17 10:15:19
I suspect it depends on two numbers: size() and di
jdoerrie
2017/05/17 11:32:05
Acknowledged.
| |
| 692 | |
| 693 if (insert_inplace) { | |
| 694 if (overwrite_existing) { | |
| 695 for (; first != last; ++first) | |
| 696 insert_or_assign(*first); | |
| 697 } else { | |
| 698 for (; first != last; ++first) | |
| 699 insert(*first); | |
|
dyaroshev
2017/05/17 10:15:19
Nit: std::copy(first, last, std::inserter(*this, e
| |
| 700 } | |
| 701 return; | |
| 702 } | |
| 703 | |
| 704 // For batch updates initialize the first insertion point. | |
| 705 const size_type original_size = size(); | |
| 706 | |
| 707 // Provide a convenience lambda to obtain an iterator pointing past the last | |
| 708 // old element. This needs to be dymanic due to possible re-allocations. | |
| 709 auto middle = [this, original_size]() { | |
| 710 return std::next(begin(), original_size); | |
| 711 }; | |
| 712 | |
| 713 // Loop over the input range while appending new values and overwriting | |
| 714 // existing ones, if applicable. | |
| 715 if (overwrite_existing) { | |
| 716 for (; first != last; ++first) | |
| 717 append_or_assign(begin(), middle(), *first); | |
| 718 } else { | |
| 719 for (; first != last; ++first) | |
| 720 append_unique(begin(), middle(), *first); | |
| 721 } | |
| 722 | |
| 723 // The new elements might be unordered and contain duplicates, so post-process | |
| 724 // the just inserted elements and merge them with the rest. Binary search for | |
| 725 // the first insertion spot. | |
| 726 sort_and_unique(middle(), end(), dupes); | |
| 727 if (middle() != end()) { | |
| 728 std::inplace_merge( | |
| 729 std::lower_bound(begin(), middle(), *middle(), value_comp()), middle(), | |
|
dyaroshev
2017/05/17 10:15:19
I really think you ought to cache binary search.
jdoerrie
2017/05/17 11:32:05
Done.
| |
| 730 end(), value_comp()); | |
| 731 } | |
| 732 } | |
| 733 | |
| 734 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | |
| 606 template <class... Args> | 735 template <class... Args> |
| 607 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::emplace(Args&&... args) | 736 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::emplace(Args&&... args) |
| 608 -> std::pair<iterator, bool> { | 737 -> std::pair<iterator, bool> { |
| 609 return insert(value_type(std::forward<Args>(args)...)); | 738 return insert(value_type(std::forward<Args>(args)...)); |
| 610 } | 739 } |
| 611 | 740 |
| 612 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 741 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
| 613 template <class... Args> | 742 template <class... Args> |
| 614 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::emplace_hint( | 743 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::emplace_hint( |
| 615 const_iterator position_hint, | 744 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>& | 897 void EraseIf(base::internal::flat_tree<Key, Value, GetKeyFromValue, KeyCompare>& |
| 769 container, | 898 container, |
| 770 Predicate pred) { | 899 Predicate pred) { |
| 771 container.erase(std::remove_if(container.begin(), container.end(), pred), | 900 container.erase(std::remove_if(container.begin(), container.end(), pred), |
| 772 container.end()); | 901 container.end()); |
| 773 } | 902 } |
| 774 | 903 |
| 775 } // namespace base | 904 } // namespace base |
| 776 | 905 |
| 777 #endif // BASE_CONTAINERS_FLAT_TREE_H_ | 906 #endif // BASE_CONTAINERS_FLAT_TREE_H_ |
| OLD | NEW |