1134723edSLouis Dionne //===----------------------------------------------------------------------===// 2134723edSLouis Dionne // 3134723edSLouis Dionne // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4134723edSLouis Dionne // See https://llvm.org/LICENSE.txt for license information. 5134723edSLouis Dionne // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6134723edSLouis Dionne // 7134723edSLouis Dionne //===----------------------------------------------------------------------===// 8134723edSLouis Dionne 9134723edSLouis Dionne #ifndef _LIBCPP___ALGORITHM_SET_INTERSECTION_H 10134723edSLouis Dionne #define _LIBCPP___ALGORITHM_SET_INTERSECTION_H 11134723edSLouis Dionne 12134723edSLouis Dionne #include <__algorithm/comp.h> 13134723edSLouis Dionne #include <__algorithm/comp_ref_type.h> 1496b674f2SHui Xie #include <__algorithm/iterator_operations.h> 15a0662176SIuri Chaer #include <__algorithm/lower_bound.h> 164d81a46fSArthur O'Dwyer #include <__config> 17a0662176SIuri Chaer #include <__functional/identity.h> 18134723edSLouis Dionne #include <__iterator/iterator_traits.h> 19101d1e9bSNikolas Klauser #include <__iterator/next.h> 20a0662176SIuri Chaer #include <__type_traits/is_same.h> 21a0662176SIuri Chaer #include <__utility/exchange.h> 22*09e3a360SLouis Dionne #include <__utility/forward.h> 2396b674f2SHui Xie #include <__utility/move.h> 24a0662176SIuri Chaer #include <__utility/swap.h> 25134723edSLouis Dionne 26134723edSLouis Dionne #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 27134723edSLouis Dionne # pragma GCC system_header 28134723edSLouis Dionne #endif 29134723edSLouis Dionne 307b462251SLouis Dionne _LIBCPP_PUSH_MACROS 317b462251SLouis Dionne #include <__undef_macros> 327b462251SLouis Dionne 33134723edSLouis Dionne _LIBCPP_BEGIN_NAMESPACE_STD 34134723edSLouis Dionne 3596b674f2SHui Xie template <class _InIter1, class _InIter2, class _OutIter> 3696b674f2SHui Xie struct __set_intersection_result { 37a5c0638dSHui Xie _InIter1 __in1_; 38a5c0638dSHui Xie _InIter2 __in2_; 39a5c0638dSHui Xie _OutIter __out_; 4096b674f2SHui Xie 4196b674f2SHui Xie // need a constructor as C++03 aggregate init is hard 425146b57bSNikolas Klauser _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 43e90e7e70SHui Xie __set_intersection_result(_InIter1&& __in_iter1, _InIter2&& __in_iter2, _OutIter&& __out_iter) 44a5c0638dSHui Xie : __in1_(std::move(__in_iter1)), __in2_(std::move(__in_iter2)), __out_(std::move(__out_iter)) {} 4596b674f2SHui Xie }; 4696b674f2SHui Xie 47a0662176SIuri Chaer // Helper for __set_intersection() with one-sided binary search: populate result and advance input iterators if they 48a0662176SIuri Chaer // are found to potentially contain the same value in two consecutive calls. This function is very intimately related to 49a0662176SIuri Chaer // the way it is used and doesn't attempt to abstract that, it's not appropriate for general usage outside of its 50a0662176SIuri Chaer // context. 51a0662176SIuri Chaer template <class _InForwardIter1, class _InForwardIter2, class _OutIter> 52a0662176SIuri Chaer _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __set_intersection_add_output_if_equal( 53a0662176SIuri Chaer bool __may_be_equal, 54a0662176SIuri Chaer _InForwardIter1& __first1, 55a0662176SIuri Chaer _InForwardIter2& __first2, 56a0662176SIuri Chaer _OutIter& __result, 57a0662176SIuri Chaer bool& __prev_may_be_equal) { 58a0662176SIuri Chaer if (__may_be_equal && __prev_may_be_equal) { 59a0662176SIuri Chaer *__result = *__first1; 60a0662176SIuri Chaer ++__result; 61a0662176SIuri Chaer ++__first1; 62a0662176SIuri Chaer ++__first2; 63a0662176SIuri Chaer __prev_may_be_equal = false; 64a0662176SIuri Chaer } else { 65a0662176SIuri Chaer __prev_may_be_equal = __may_be_equal; 66a0662176SIuri Chaer } 67a0662176SIuri Chaer } 68a0662176SIuri Chaer 69a0662176SIuri Chaer // With forward iterators we can make multiple passes over the data, allowing the use of one-sided binary search to 70a0662176SIuri Chaer // reduce best-case complexity to log(N). Understanding how we can use binary search and still respect complexity 71a0662176SIuri Chaer // guarantees is _not_ straightforward: the guarantee is "at most 2*(N+M)-1 comparisons", and one-sided binary search 72a0662176SIuri Chaer // will necessarily overshoot depending on the position of the needle in the haystack -- for instance, if we're 73a0662176SIuri Chaer // searching for 3 in (1, 2, 3, 4), we'll check if 3<1, then 3<2, then 3<4, and, finally, 3<3, for a total of 4 74a0662176SIuri Chaer // comparisons, when linear search would have yielded 3. However, because we won't need to perform the intervening 75a0662176SIuri Chaer // reciprocal comparisons (ie 1<3, 2<3, 4<3), that extra comparison doesn't run afoul of the guarantee. Additionally, 76a0662176SIuri Chaer // this type of scenario can only happen for match distances of up to 5 elements, because 2*log2(8) is 6, and we'll 77a0662176SIuri Chaer // still be worse-off at position 5 of an 8-element set. From then onwards these scenarios can't happen. TL;DR: we'll be 78a0662176SIuri Chaer // 1 comparison worse-off compared to the classic linear-searching algorithm if matching position 3 of a set with 4 79a0662176SIuri Chaer // elements, or position 5 if the set has 7 or 8 elements, but we'll never exceed the complexity guarantees from the 80a0662176SIuri Chaer // standard. 81a0662176SIuri Chaer template <class _AlgPolicy, 82a0662176SIuri Chaer class _Compare, 83a0662176SIuri Chaer class _InForwardIter1, 84a0662176SIuri Chaer class _Sent1, 85a0662176SIuri Chaer class _InForwardIter2, 86a0662176SIuri Chaer class _Sent2, 87a0662176SIuri Chaer class _OutIter> 8817e0686aSNikolas Klauser [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI 89a0662176SIuri Chaer _LIBCPP_CONSTEXPR_SINCE_CXX20 __set_intersection_result<_InForwardIter1, _InForwardIter2, _OutIter> 9096b674f2SHui Xie __set_intersection( 91a0662176SIuri Chaer _InForwardIter1 __first1, 92a0662176SIuri Chaer _Sent1 __last1, 93a0662176SIuri Chaer _InForwardIter2 __first2, 94a0662176SIuri Chaer _Sent2 __last2, 95a0662176SIuri Chaer _OutIter __result, 96a0662176SIuri Chaer _Compare&& __comp, 97a0662176SIuri Chaer std::forward_iterator_tag, 98a0662176SIuri Chaer std::forward_iterator_tag) { 99a0662176SIuri Chaer _LIBCPP_CONSTEXPR std::__identity __proj; 100a0662176SIuri Chaer bool __prev_may_be_equal = false; 101a0662176SIuri Chaer 102a0662176SIuri Chaer while (__first2 != __last2) { 103a0662176SIuri Chaer _InForwardIter1 __first1_next = 104a0662176SIuri Chaer std::__lower_bound_onesided<_AlgPolicy>(__first1, __last1, *__first2, __comp, __proj); 105a0662176SIuri Chaer std::swap(__first1_next, __first1); 106a0662176SIuri Chaer // keeping in mind that a==b iff !(a<b) && !(b<a): 107a0662176SIuri Chaer // if we can't advance __first1, that means !(*__first1 < *_first2), therefore __may_be_equal==true 108a0662176SIuri Chaer std::__set_intersection_add_output_if_equal( 109a0662176SIuri Chaer __first1 == __first1_next, __first1, __first2, __result, __prev_may_be_equal); 110a0662176SIuri Chaer if (__first1 == __last1) 111a0662176SIuri Chaer break; 112a0662176SIuri Chaer 113a0662176SIuri Chaer _InForwardIter2 __first2_next = 114a0662176SIuri Chaer std::__lower_bound_onesided<_AlgPolicy>(__first2, __last2, *__first1, __comp, __proj); 115a0662176SIuri Chaer std::swap(__first2_next, __first2); 116a0662176SIuri Chaer std::__set_intersection_add_output_if_equal( 117a0662176SIuri Chaer __first2 == __first2_next, __first1, __first2, __result, __prev_may_be_equal); 118a0662176SIuri Chaer } 119a0662176SIuri Chaer return __set_intersection_result<_InForwardIter1, _InForwardIter2, _OutIter>( 120a0662176SIuri Chaer _IterOps<_AlgPolicy>::next(std::move(__first1), std::move(__last1)), 121a0662176SIuri Chaer _IterOps<_AlgPolicy>::next(std::move(__first2), std::move(__last2)), 122a0662176SIuri Chaer std::move(__result)); 123a0662176SIuri Chaer } 124a0662176SIuri Chaer 125a0662176SIuri Chaer // input iterators are not suitable for multipass algorithms, so we stick to the classic single-pass version 126a0662176SIuri Chaer template <class _AlgPolicy, 127a0662176SIuri Chaer class _Compare, 128a0662176SIuri Chaer class _InInputIter1, 129a0662176SIuri Chaer class _Sent1, 130a0662176SIuri Chaer class _InInputIter2, 131a0662176SIuri Chaer class _Sent2, 132a0662176SIuri Chaer class _OutIter> 13317e0686aSNikolas Klauser [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI 134a0662176SIuri Chaer _LIBCPP_CONSTEXPR_SINCE_CXX20 __set_intersection_result<_InInputIter1, _InInputIter2, _OutIter> 135a0662176SIuri Chaer __set_intersection( 136a0662176SIuri Chaer _InInputIter1 __first1, 137a0662176SIuri Chaer _Sent1 __last1, 138a0662176SIuri Chaer _InInputIter2 __first2, 139a0662176SIuri Chaer _Sent2 __last2, 140a0662176SIuri Chaer _OutIter __result, 141a0662176SIuri Chaer _Compare&& __comp, 142a0662176SIuri Chaer std::input_iterator_tag, 143a0662176SIuri Chaer std::input_iterator_tag) { 14496b674f2SHui Xie while (__first1 != __last1 && __first2 != __last2) { 145134723edSLouis Dionne if (__comp(*__first1, *__first2)) 146134723edSLouis Dionne ++__first1; 14796b674f2SHui Xie else { 14896b674f2SHui Xie if (!__comp(*__first2, *__first1)) { 149134723edSLouis Dionne *__result = *__first1; 150134723edSLouis Dionne ++__result; 151134723edSLouis Dionne ++__first1; 152134723edSLouis Dionne } 153134723edSLouis Dionne ++__first2; 154134723edSLouis Dionne } 155134723edSLouis Dionne } 15696b674f2SHui Xie 157a0662176SIuri Chaer return __set_intersection_result<_InInputIter1, _InInputIter2, _OutIter>( 158295b951eSKonstantin Varlamov _IterOps<_AlgPolicy>::next(std::move(__first1), std::move(__last1)), 159295b951eSKonstantin Varlamov _IterOps<_AlgPolicy>::next(std::move(__first2), std::move(__last2)), 16096b674f2SHui Xie std::move(__result)); 161134723edSLouis Dionne } 162134723edSLouis Dionne 163a0662176SIuri Chaer template <class _AlgPolicy, class _Compare, class _InIter1, class _Sent1, class _InIter2, class _Sent2, class _OutIter> 16417e0686aSNikolas Klauser [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI 165a0662176SIuri Chaer _LIBCPP_CONSTEXPR_SINCE_CXX20 __set_intersection_result<_InIter1, _InIter2, _OutIter> 166a0662176SIuri Chaer __set_intersection( 167a0662176SIuri Chaer _InIter1 __first1, _Sent1 __last1, _InIter2 __first2, _Sent2 __last2, _OutIter __result, _Compare&& __comp) { 168a0662176SIuri Chaer return std::__set_intersection<_AlgPolicy>( 169a0662176SIuri Chaer std::move(__first1), 170a0662176SIuri Chaer std::move(__last1), 171a0662176SIuri Chaer std::move(__first2), 172a0662176SIuri Chaer std::move(__last2), 173a0662176SIuri Chaer std::move(__result), 174a0662176SIuri Chaer std::forward<_Compare>(__comp), 175a0662176SIuri Chaer typename std::_IterOps<_AlgPolicy>::template __iterator_category<_InIter1>(), 176a0662176SIuri Chaer typename std::_IterOps<_AlgPolicy>::template __iterator_category<_InIter2>()); 177a0662176SIuri Chaer } 178a0662176SIuri Chaer 179134723edSLouis Dionne template <class _InputIterator1, class _InputIterator2, class _OutputIterator, class _Compare> 1805146b57bSNikolas Klauser inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator set_intersection( 18196b674f2SHui Xie _InputIterator1 __first1, 18296b674f2SHui Xie _InputIterator1 __last1, 18396b674f2SHui Xie _InputIterator2 __first2, 18496b674f2SHui Xie _InputIterator2 __last2, 18596b674f2SHui Xie _OutputIterator __result, 18696b674f2SHui Xie _Compare __comp) { 187ed2d3644SNikolas Klauser return std::__set_intersection<_ClassicAlgPolicy, __comp_ref_type<_Compare> >( 18896b674f2SHui Xie std::move(__first1), 18996b674f2SHui Xie std::move(__last1), 19096b674f2SHui Xie std::move(__first2), 19196b674f2SHui Xie std::move(__last2), 19296b674f2SHui Xie std::move(__result), 19396b674f2SHui Xie __comp) 194a5c0638dSHui Xie .__out_; 195134723edSLouis Dionne } 196134723edSLouis Dionne 197134723edSLouis Dionne template <class _InputIterator1, class _InputIterator2, class _OutputIterator> 1985146b57bSNikolas Klauser inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator set_intersection( 19996b674f2SHui Xie _InputIterator1 __first1, 20096b674f2SHui Xie _InputIterator1 __last1, 20196b674f2SHui Xie _InputIterator2 __first2, 20296b674f2SHui Xie _InputIterator2 __last2, 20396b674f2SHui Xie _OutputIterator __result) { 204295b951eSKonstantin Varlamov return std::__set_intersection<_ClassicAlgPolicy>( 20596b674f2SHui Xie std::move(__first1), 20696b674f2SHui Xie std::move(__last1), 20796b674f2SHui Xie std::move(__first2), 20896b674f2SHui Xie std::move(__last2), 20996b674f2SHui Xie std::move(__result), 21088632e48SNikolas Klauser __less<>()) 211a5c0638dSHui Xie .__out_; 212134723edSLouis Dionne } 213134723edSLouis Dionne 214134723edSLouis Dionne _LIBCPP_END_NAMESPACE_STD 215134723edSLouis Dionne 2167b462251SLouis Dionne _LIBCPP_POP_MACROS 2177b462251SLouis Dionne 218134723edSLouis Dionne #endif // _LIBCPP___ALGORITHM_SET_INTERSECTION_H 219