1e78f53d1SNikolas Klauser //===----------------------------------------------------------------------===// 2e78f53d1SNikolas Klauser // 3e78f53d1SNikolas Klauser // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e78f53d1SNikolas Klauser // See https://llvm.org/LICENSE.txt for license information. 5e78f53d1SNikolas Klauser // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e78f53d1SNikolas Klauser // 7e78f53d1SNikolas Klauser //===----------------------------------------------------------------------===// 8e78f53d1SNikolas Klauser 9*ce777190SNikolas Klauser #ifndef _LIBCPP___CXX03___ALGORITHM_SET_INTERSECTION_H 10*ce777190SNikolas Klauser #define _LIBCPP___CXX03___ALGORITHM_SET_INTERSECTION_H 11e78f53d1SNikolas Klauser 1273fbae83SNikolas Klauser #include <__cxx03/__algorithm/comp.h> 1373fbae83SNikolas Klauser #include <__cxx03/__algorithm/comp_ref_type.h> 1473fbae83SNikolas Klauser #include <__cxx03/__algorithm/iterator_operations.h> 1573fbae83SNikolas Klauser #include <__cxx03/__algorithm/lower_bound.h> 1673fbae83SNikolas Klauser #include <__cxx03/__config> 1773fbae83SNikolas Klauser #include <__cxx03/__functional/identity.h> 1873fbae83SNikolas Klauser #include <__cxx03/__iterator/iterator_traits.h> 1973fbae83SNikolas Klauser #include <__cxx03/__iterator/next.h> 2073fbae83SNikolas Klauser #include <__cxx03/__type_traits/is_same.h> 2173fbae83SNikolas Klauser #include <__cxx03/__utility/exchange.h> 2273fbae83SNikolas Klauser #include <__cxx03/__utility/move.h> 2373fbae83SNikolas Klauser #include <__cxx03/__utility/swap.h> 24e78f53d1SNikolas Klauser 25e78f53d1SNikolas Klauser #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 26e78f53d1SNikolas Klauser # pragma GCC system_header 27e78f53d1SNikolas Klauser #endif 28e78f53d1SNikolas Klauser 29e78f53d1SNikolas Klauser _LIBCPP_PUSH_MACROS 3073fbae83SNikolas Klauser #include <__cxx03/__undef_macros> 31e78f53d1SNikolas Klauser 32e78f53d1SNikolas Klauser _LIBCPP_BEGIN_NAMESPACE_STD 33e78f53d1SNikolas Klauser 34e78f53d1SNikolas Klauser template <class _InIter1, class _InIter2, class _OutIter> 35e78f53d1SNikolas Klauser struct __set_intersection_result { 36e78f53d1SNikolas Klauser _InIter1 __in1_; 37e78f53d1SNikolas Klauser _InIter2 __in2_; 38e78f53d1SNikolas Klauser _OutIter __out_; 39e78f53d1SNikolas Klauser 40e78f53d1SNikolas Klauser // need a constructor as C++03 aggregate init is hard 41e78f53d1SNikolas Klauser _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 42e78f53d1SNikolas Klauser __set_intersection_result(_InIter1&& __in_iter1, _InIter2&& __in_iter2, _OutIter&& __out_iter) 43e78f53d1SNikolas Klauser : __in1_(std::move(__in_iter1)), __in2_(std::move(__in_iter2)), __out_(std::move(__out_iter)) {} 44e78f53d1SNikolas Klauser }; 45e78f53d1SNikolas Klauser 46e78f53d1SNikolas Klauser // Helper for __set_intersection() with one-sided binary search: populate result and advance input iterators if they 47e78f53d1SNikolas Klauser // are found to potentially contain the same value in two consecutive calls. This function is very intimately related to 48e78f53d1SNikolas Klauser // the way it is used and doesn't attempt to abstract that, it's not appropriate for general usage outside of its 49e78f53d1SNikolas Klauser // context. 50e78f53d1SNikolas Klauser template <class _InForwardIter1, class _InForwardIter2, class _OutIter> 51e78f53d1SNikolas Klauser _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __set_intersection_add_output_if_equal( 52e78f53d1SNikolas Klauser bool __may_be_equal, 53e78f53d1SNikolas Klauser _InForwardIter1& __first1, 54e78f53d1SNikolas Klauser _InForwardIter2& __first2, 55e78f53d1SNikolas Klauser _OutIter& __result, 56e78f53d1SNikolas Klauser bool& __prev_may_be_equal) { 57e78f53d1SNikolas Klauser if (__may_be_equal && __prev_may_be_equal) { 58e78f53d1SNikolas Klauser *__result = *__first1; 59e78f53d1SNikolas Klauser ++__result; 60e78f53d1SNikolas Klauser ++__first1; 61e78f53d1SNikolas Klauser ++__first2; 62e78f53d1SNikolas Klauser __prev_may_be_equal = false; 63e78f53d1SNikolas Klauser } else { 64e78f53d1SNikolas Klauser __prev_may_be_equal = __may_be_equal; 65e78f53d1SNikolas Klauser } 66e78f53d1SNikolas Klauser } 67e78f53d1SNikolas Klauser 68e78f53d1SNikolas Klauser // With forward iterators we can make multiple passes over the data, allowing the use of one-sided binary search to 69e78f53d1SNikolas Klauser // reduce best-case complexity to log(N). Understanding how we can use binary search and still respect complexity 70e78f53d1SNikolas Klauser // guarantees is _not_ straightforward: the guarantee is "at most 2*(N+M)-1 comparisons", and one-sided binary search 71e78f53d1SNikolas Klauser // will necessarily overshoot depending on the position of the needle in the haystack -- for instance, if we're 72e78f53d1SNikolas Klauser // 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 73e78f53d1SNikolas Klauser // comparisons, when linear search would have yielded 3. However, because we won't need to perform the intervening 74e78f53d1SNikolas Klauser // reciprocal comparisons (ie 1<3, 2<3, 4<3), that extra comparison doesn't run afoul of the guarantee. Additionally, 75e78f53d1SNikolas Klauser // this type of scenario can only happen for match distances of up to 5 elements, because 2*log2(8) is 6, and we'll 76e78f53d1SNikolas Klauser // 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 77e78f53d1SNikolas Klauser // 1 comparison worse-off compared to the classic linear-searching algorithm if matching position 3 of a set with 4 78e78f53d1SNikolas Klauser // elements, or position 5 if the set has 7 or 8 elements, but we'll never exceed the complexity guarantees from the 79e78f53d1SNikolas Klauser // standard. 80e78f53d1SNikolas Klauser template <class _AlgPolicy, 81e78f53d1SNikolas Klauser class _Compare, 82e78f53d1SNikolas Klauser class _InForwardIter1, 83e78f53d1SNikolas Klauser class _Sent1, 84e78f53d1SNikolas Klauser class _InForwardIter2, 85e78f53d1SNikolas Klauser class _Sent2, 86e78f53d1SNikolas Klauser class _OutIter> 87e78f53d1SNikolas Klauser _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI 88e78f53d1SNikolas Klauser _LIBCPP_CONSTEXPR_SINCE_CXX20 __set_intersection_result<_InForwardIter1, _InForwardIter2, _OutIter> 89e78f53d1SNikolas Klauser __set_intersection( 90e78f53d1SNikolas Klauser _InForwardIter1 __first1, 91e78f53d1SNikolas Klauser _Sent1 __last1, 92e78f53d1SNikolas Klauser _InForwardIter2 __first2, 93e78f53d1SNikolas Klauser _Sent2 __last2, 94e78f53d1SNikolas Klauser _OutIter __result, 95e78f53d1SNikolas Klauser _Compare&& __comp, 96e78f53d1SNikolas Klauser std::forward_iterator_tag, 97e78f53d1SNikolas Klauser std::forward_iterator_tag) { 98e78f53d1SNikolas Klauser _LIBCPP_CONSTEXPR std::__identity __proj; 99e78f53d1SNikolas Klauser bool __prev_may_be_equal = false; 100e78f53d1SNikolas Klauser 101e78f53d1SNikolas Klauser while (__first2 != __last2) { 102e78f53d1SNikolas Klauser _InForwardIter1 __first1_next = 103e78f53d1SNikolas Klauser std::__lower_bound_onesided<_AlgPolicy>(__first1, __last1, *__first2, __comp, __proj); 104e78f53d1SNikolas Klauser std::swap(__first1_next, __first1); 105e78f53d1SNikolas Klauser // keeping in mind that a==b iff !(a<b) && !(b<a): 106e78f53d1SNikolas Klauser // if we can't advance __first1, that means !(*__first1 < *_first2), therefore __may_be_equal==true 107e78f53d1SNikolas Klauser std::__set_intersection_add_output_if_equal( 108e78f53d1SNikolas Klauser __first1 == __first1_next, __first1, __first2, __result, __prev_may_be_equal); 109e78f53d1SNikolas Klauser if (__first1 == __last1) 110e78f53d1SNikolas Klauser break; 111e78f53d1SNikolas Klauser 112e78f53d1SNikolas Klauser _InForwardIter2 __first2_next = 113e78f53d1SNikolas Klauser std::__lower_bound_onesided<_AlgPolicy>(__first2, __last2, *__first1, __comp, __proj); 114e78f53d1SNikolas Klauser std::swap(__first2_next, __first2); 115e78f53d1SNikolas Klauser std::__set_intersection_add_output_if_equal( 116e78f53d1SNikolas Klauser __first2 == __first2_next, __first1, __first2, __result, __prev_may_be_equal); 117e78f53d1SNikolas Klauser } 118e78f53d1SNikolas Klauser return __set_intersection_result<_InForwardIter1, _InForwardIter2, _OutIter>( 119e78f53d1SNikolas Klauser _IterOps<_AlgPolicy>::next(std::move(__first1), std::move(__last1)), 120e78f53d1SNikolas Klauser _IterOps<_AlgPolicy>::next(std::move(__first2), std::move(__last2)), 121e78f53d1SNikolas Klauser std::move(__result)); 122e78f53d1SNikolas Klauser } 123e78f53d1SNikolas Klauser 124e78f53d1SNikolas Klauser // input iterators are not suitable for multipass algorithms, so we stick to the classic single-pass version 125e78f53d1SNikolas Klauser template <class _AlgPolicy, 126e78f53d1SNikolas Klauser class _Compare, 127e78f53d1SNikolas Klauser class _InInputIter1, 128e78f53d1SNikolas Klauser class _Sent1, 129e78f53d1SNikolas Klauser class _InInputIter2, 130e78f53d1SNikolas Klauser class _Sent2, 131e78f53d1SNikolas Klauser class _OutIter> 132e78f53d1SNikolas Klauser _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI 133e78f53d1SNikolas Klauser _LIBCPP_CONSTEXPR_SINCE_CXX20 __set_intersection_result<_InInputIter1, _InInputIter2, _OutIter> 134e78f53d1SNikolas Klauser __set_intersection( 135e78f53d1SNikolas Klauser _InInputIter1 __first1, 136e78f53d1SNikolas Klauser _Sent1 __last1, 137e78f53d1SNikolas Klauser _InInputIter2 __first2, 138e78f53d1SNikolas Klauser _Sent2 __last2, 139e78f53d1SNikolas Klauser _OutIter __result, 140e78f53d1SNikolas Klauser _Compare&& __comp, 141e78f53d1SNikolas Klauser std::input_iterator_tag, 142e78f53d1SNikolas Klauser std::input_iterator_tag) { 143e78f53d1SNikolas Klauser while (__first1 != __last1 && __first2 != __last2) { 144e78f53d1SNikolas Klauser if (__comp(*__first1, *__first2)) 145e78f53d1SNikolas Klauser ++__first1; 146e78f53d1SNikolas Klauser else { 147e78f53d1SNikolas Klauser if (!__comp(*__first2, *__first1)) { 148e78f53d1SNikolas Klauser *__result = *__first1; 149e78f53d1SNikolas Klauser ++__result; 150e78f53d1SNikolas Klauser ++__first1; 151e78f53d1SNikolas Klauser } 152e78f53d1SNikolas Klauser ++__first2; 153e78f53d1SNikolas Klauser } 154e78f53d1SNikolas Klauser } 155e78f53d1SNikolas Klauser 156e78f53d1SNikolas Klauser return __set_intersection_result<_InInputIter1, _InInputIter2, _OutIter>( 157e78f53d1SNikolas Klauser _IterOps<_AlgPolicy>::next(std::move(__first1), std::move(__last1)), 158e78f53d1SNikolas Klauser _IterOps<_AlgPolicy>::next(std::move(__first2), std::move(__last2)), 159e78f53d1SNikolas Klauser std::move(__result)); 160e78f53d1SNikolas Klauser } 161e78f53d1SNikolas Klauser 162e78f53d1SNikolas Klauser template <class _AlgPolicy, class _Compare, class _InIter1, class _Sent1, class _InIter2, class _Sent2, class _OutIter> 163e78f53d1SNikolas Klauser _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI 164e78f53d1SNikolas Klauser _LIBCPP_CONSTEXPR_SINCE_CXX20 __set_intersection_result<_InIter1, _InIter2, _OutIter> 165e78f53d1SNikolas Klauser __set_intersection( 166e78f53d1SNikolas Klauser _InIter1 __first1, _Sent1 __last1, _InIter2 __first2, _Sent2 __last2, _OutIter __result, _Compare&& __comp) { 167e78f53d1SNikolas Klauser return std::__set_intersection<_AlgPolicy>( 168e78f53d1SNikolas Klauser std::move(__first1), 169e78f53d1SNikolas Klauser std::move(__last1), 170e78f53d1SNikolas Klauser std::move(__first2), 171e78f53d1SNikolas Klauser std::move(__last2), 172e78f53d1SNikolas Klauser std::move(__result), 173e78f53d1SNikolas Klauser std::forward<_Compare>(__comp), 174e78f53d1SNikolas Klauser typename std::_IterOps<_AlgPolicy>::template __iterator_category<_InIter1>(), 175e78f53d1SNikolas Klauser typename std::_IterOps<_AlgPolicy>::template __iterator_category<_InIter2>()); 176e78f53d1SNikolas Klauser } 177e78f53d1SNikolas Klauser 178e78f53d1SNikolas Klauser template <class _InputIterator1, class _InputIterator2, class _OutputIterator, class _Compare> 179e78f53d1SNikolas Klauser inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator set_intersection( 180e78f53d1SNikolas Klauser _InputIterator1 __first1, 181e78f53d1SNikolas Klauser _InputIterator1 __last1, 182e78f53d1SNikolas Klauser _InputIterator2 __first2, 183e78f53d1SNikolas Klauser _InputIterator2 __last2, 184e78f53d1SNikolas Klauser _OutputIterator __result, 185e78f53d1SNikolas Klauser _Compare __comp) { 186e78f53d1SNikolas Klauser return std::__set_intersection<_ClassicAlgPolicy, __comp_ref_type<_Compare> >( 187e78f53d1SNikolas Klauser std::move(__first1), 188e78f53d1SNikolas Klauser std::move(__last1), 189e78f53d1SNikolas Klauser std::move(__first2), 190e78f53d1SNikolas Klauser std::move(__last2), 191e78f53d1SNikolas Klauser std::move(__result), 192e78f53d1SNikolas Klauser __comp) 193e78f53d1SNikolas Klauser .__out_; 194e78f53d1SNikolas Klauser } 195e78f53d1SNikolas Klauser 196e78f53d1SNikolas Klauser template <class _InputIterator1, class _InputIterator2, class _OutputIterator> 197e78f53d1SNikolas Klauser inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator set_intersection( 198e78f53d1SNikolas Klauser _InputIterator1 __first1, 199e78f53d1SNikolas Klauser _InputIterator1 __last1, 200e78f53d1SNikolas Klauser _InputIterator2 __first2, 201e78f53d1SNikolas Klauser _InputIterator2 __last2, 202e78f53d1SNikolas Klauser _OutputIterator __result) { 203e78f53d1SNikolas Klauser return std::__set_intersection<_ClassicAlgPolicy>( 204e78f53d1SNikolas Klauser std::move(__first1), 205e78f53d1SNikolas Klauser std::move(__last1), 206e78f53d1SNikolas Klauser std::move(__first2), 207e78f53d1SNikolas Klauser std::move(__last2), 208e78f53d1SNikolas Klauser std::move(__result), 209e78f53d1SNikolas Klauser __less<>()) 210e78f53d1SNikolas Klauser .__out_; 211e78f53d1SNikolas Klauser } 212e78f53d1SNikolas Klauser 213e78f53d1SNikolas Klauser _LIBCPP_END_NAMESPACE_STD 214e78f53d1SNikolas Klauser 215e78f53d1SNikolas Klauser _LIBCPP_POP_MACROS 216e78f53d1SNikolas Klauser 217*ce777190SNikolas Klauser #endif // _LIBCPP___CXX03___ALGORITHM_SET_INTERSECTION_H 218