|
11 | 11 | #define _LIBCPP___TREE |
12 | 12 |
|
13 | 13 | #include <__algorithm/min.h> |
| 14 | +#include <__algorithm/specialized_algorithms.h> |
14 | 15 | #include <__assert> |
15 | 16 | #include <__config> |
16 | 17 | #include <__fwd/pair.h> |
|
36 | 37 | #include <__type_traits/is_swappable.h> |
37 | 38 | #include <__type_traits/make_transparent.h> |
38 | 39 | #include <__type_traits/remove_const.h> |
| 40 | +#include <__type_traits/remove_cvref.h> |
39 | 41 | #include <__utility/forward.h> |
40 | 42 | #include <__utility/lazy_synth_three_way_comparator.h> |
41 | 43 | #include <__utility/move.h> |
@@ -656,6 +658,50 @@ struct __generic_container_node_destructor<__tree_node<_Tp, _VoidPtr>, _Alloc> : |
656 | 658 | }; |
657 | 659 | #endif |
658 | 660 |
|
| 661 | +// Do an in-order traversal of the tree until `__break` returns true. Takes the root node of the tree. |
| 662 | +template <class _Reference, class _Break, class _NodePtr, class _Func, class _Proj> |
| 663 | +_LIBCPP_HIDE_FROM_ABI bool __tree_iterate_from_root(_Break __break, _NodePtr __root, _Func& __func, _Proj& __proj) { |
| 664 | + if (__root->__left_) { |
| 665 | + if (std::__tree_iterate_from_root<_Reference>(__break, static_cast<_NodePtr>(__root->__left_), __func, __proj)) |
| 666 | + return true; |
| 667 | + } |
| 668 | + if (__break(__root)) |
| 669 | + return true; |
| 670 | + __func(static_cast<_Reference>(__root->__get_value())); |
| 671 | + if (__root->__right_) |
| 672 | + return std::__tree_iterate_from_root<_Reference>(__break, static_cast<_NodePtr>(__root->__right_), __func, __proj); |
| 673 | + return false; |
| 674 | +} |
| 675 | + |
| 676 | +// Do an in-order traversal of the tree from __first to __last. |
| 677 | +template <class _NodeIter, class _Func, class _Proj> |
| 678 | +_LIBCPP_HIDE_FROM_ABI void |
| 679 | +__tree_iterate_subrange(_NodeIter __first_it, _NodeIter __last_it, _Func& __func, _Proj& __proj) { |
| 680 | + using _NodePtr = _NodeIter::__node_pointer; |
| 681 | + using _Reference = _NodeIter::reference; |
| 682 | + |
| 683 | + auto __first = __first_it.__ptr_; |
| 684 | + auto __last = __last_it.__ptr_; |
| 685 | + |
| 686 | + while (true) { |
| 687 | + if (__first == __last) |
| 688 | + return; |
| 689 | + const auto __nfirst = static_cast<_NodePtr>(__first); |
| 690 | + __func(static_cast<_Reference>(__nfirst->__get_value())); |
| 691 | + if (__nfirst->__right_) { |
| 692 | + if (std::__tree_iterate_from_root<_Reference>( |
| 693 | + [&](_NodePtr __node) -> bool { return __node == __last; }, |
| 694 | + static_cast<_NodePtr>(__nfirst->__right_), |
| 695 | + __func, |
| 696 | + __proj)) |
| 697 | + return; |
| 698 | + } |
| 699 | + while (!std::__tree_is_left_child(static_cast<_NodePtr>(__first))) |
| 700 | + __first = static_cast<_NodePtr>(__first)->__parent_; |
| 701 | + __first = static_cast<_NodePtr>(__first)->__parent_; |
| 702 | + } |
| 703 | +} |
| 704 | + |
659 | 705 | template <class _Tp, class _NodePtr, class _DiffType> |
660 | 706 | class __tree_iterator { |
661 | 707 | using _NodeTypes _LIBCPP_NODEBUG = __tree_node_types<_NodePtr>; |
@@ -715,8 +761,28 @@ private: |
715 | 761 | friend class __tree; |
716 | 762 | template <class, class, class> |
717 | 763 | friend class __tree_const_iterator; |
| 764 | + |
| 765 | + template <class _NodeIter, class _Func, class _Proj> |
| 766 | + friend void __tree_iterate_subrange(_NodeIter, _NodeIter, _Func&, _Proj&); |
718 | 767 | }; |
719 | 768 |
|
| 769 | +#ifndef _LIBCPP_CXX03_LANG |
| 770 | +// This also handles {multi,}set::iterator, since they're just aliases to __tree::iterator |
| 771 | +template <class _Tp, class _NodePtr, class _DiffType> |
| 772 | +struct __specialized_algorithm< |
| 773 | + _Algorithm::__for_each, |
| 774 | + __iterator_pair<__tree_iterator<_Tp, _NodePtr, _DiffType>, __tree_iterator<_Tp, _NodePtr, _DiffType>>> { |
| 775 | + static const bool __has_algorithm = true; |
| 776 | + |
| 777 | + using __iterator _LIBCPP_NODEBUG = __tree_iterator<_Tp, _NodePtr, _DiffType>; |
| 778 | + |
| 779 | + template <class _Func, class _Proj> |
| 780 | + _LIBCPP_HIDE_FROM_ABI static void operator()(__iterator __first, __iterator __last, _Func& __func, _Proj& __proj) { |
| 781 | + std::__tree_iterate_subrange(__first, __last, __func, __proj); |
| 782 | + } |
| 783 | +}; |
| 784 | +#endif |
| 785 | + |
720 | 786 | template <class _Tp, class _NodePtr, class _DiffType> |
721 | 787 | class __tree_const_iterator { |
722 | 788 | using _NodeTypes _LIBCPP_NODEBUG = __tree_node_types<_NodePtr>; |
@@ -780,7 +846,27 @@ private: |
780 | 846 |
|
781 | 847 | template <class, class, class> |
782 | 848 | friend class __tree; |
| 849 | + |
| 850 | + template <class _NodeIter, class _Func, class _Proj> |
| 851 | + friend void __tree_iterate_subrange(_NodeIter, _NodeIter, _Func&, _Proj&); |
| 852 | +}; |
| 853 | + |
| 854 | +#ifndef _LIBCPP_CXX03_LANG |
| 855 | +// This also handles {multi,}set::const_iterator, since they're just aliases to __tree::iterator |
| 856 | +template <class _Tp, class _NodePtr, class _DiffType> |
| 857 | +struct __specialized_algorithm< |
| 858 | + _Algorithm::__for_each, |
| 859 | + __iterator_pair<__tree_const_iterator<_Tp, _NodePtr, _DiffType>, __tree_const_iterator<_Tp, _NodePtr, _DiffType>>> { |
| 860 | + static const bool __has_algorithm = true; |
| 861 | + |
| 862 | + using __iterator _LIBCPP_NODEBUG = __tree_const_iterator<_Tp, _NodePtr, _DiffType>; |
| 863 | + |
| 864 | + template <class _Func, class _Proj> |
| 865 | + _LIBCPP_HIDE_FROM_ABI static void operator()(__iterator __first, __iterator __last, _Func& __func, _Proj& __proj) { |
| 866 | + std::__tree_iterate_subrange(__first, __last, __func, __proj); |
| 867 | + } |
783 | 868 | }; |
| 869 | +#endif |
784 | 870 |
|
785 | 871 | template <class _Tp, class _Compare> |
786 | 872 | #ifndef _LIBCPP_CXX03_LANG |
@@ -1484,7 +1570,25 @@ private: |
1484 | 1570 | [](value_type& __lhs, value_type& __rhs) { __assign_value(__lhs, std::move(__rhs)); }, |
1485 | 1571 | [this](__node_pointer __nd) { return __move_construct_tree(__nd); }); |
1486 | 1572 | } |
| 1573 | + |
| 1574 | + friend struct __specialized_algorithm<_Algorithm::__for_each, __single_range<__tree> >; |
| 1575 | +}; |
| 1576 | + |
| 1577 | +#if _LIBCPP_STD_VER >= 14 |
| 1578 | +template <class _Tp, class _Compare, class _Allocator> |
| 1579 | +struct __specialized_algorithm<_Algorithm::__for_each, __single_range<__tree<_Tp, _Compare, _Allocator> > > { |
| 1580 | + static const bool __has_algorithm = true; |
| 1581 | + |
| 1582 | + using __node_pointer _LIBCPP_NODEBUG = typename __tree<_Tp, _Compare, _Allocator>::__node_pointer; |
| 1583 | + |
| 1584 | + template <class _Tree, class _Func, class _Proj> |
| 1585 | + _LIBCPP_HIDE_FROM_ABI static auto operator()(_Tree&& __range, _Func __func, _Proj __proj) { |
| 1586 | + std::__tree_iterate_from_root<__copy_cvref_t<_Tree, typename __remove_cvref_t<_Tree>::value_type>>( |
| 1587 | + [](__node_pointer) { return false; }, __range.__root(), __func, __proj); |
| 1588 | + return std::make_pair(__range.end(), std::move(__func)); |
| 1589 | + } |
1487 | 1590 | }; |
| 1591 | +#endif |
1488 | 1592 |
|
1489 | 1593 | // Precondition: __size_ != 0 |
1490 | 1594 | template <class _Tp, class _Compare, class _Allocator> |
|
0 commit comments