master
  1//===----------------------------------------------------------------------===//
  2//
  3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4// See https://llvm.org/LICENSE.txt for license information.
  5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6//
  7//===----------------------------------------------------------------------===//
  8
  9#ifndef _LIBCPP___ALGORITHM_RANGES_ENDS_WITH_H
 10#define _LIBCPP___ALGORITHM_RANGES_ENDS_WITH_H
 11
 12#include <__algorithm/ranges_equal.h>
 13#include <__algorithm/ranges_starts_with.h>
 14#include <__config>
 15#include <__functional/identity.h>
 16#include <__functional/ranges_operations.h>
 17#include <__functional/reference_wrapper.h>
 18#include <__iterator/advance.h>
 19#include <__iterator/concepts.h>
 20#include <__iterator/distance.h>
 21#include <__iterator/indirectly_comparable.h>
 22#include <__iterator/reverse_iterator.h>
 23#include <__ranges/access.h>
 24#include <__ranges/concepts.h>
 25#include <__ranges/size.h>
 26#include <__utility/move.h>
 27
 28#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 29#  pragma GCC system_header
 30#endif
 31
 32_LIBCPP_PUSH_MACROS
 33#include <__undef_macros>
 34
 35#if _LIBCPP_STD_VER >= 23
 36
 37_LIBCPP_BEGIN_NAMESPACE_STD
 38
 39namespace ranges {
 40struct __ends_with {
 41  template <class _Iter1, class _Sent1, class _Iter2, class _Sent2, class _Pred, class _Proj1, class _Proj2>
 42  _LIBCPP_HIDE_FROM_ABI static constexpr bool __ends_with_fn_impl_bidirectional(
 43      _Iter1 __first1,
 44      _Sent1 __last1,
 45      _Iter2 __first2,
 46      _Sent2 __last2,
 47      _Pred& __pred,
 48      _Proj1& __proj1,
 49      _Proj2& __proj2) {
 50    auto __rbegin1 = std::make_reverse_iterator(__last1);
 51    auto __rend1   = std::make_reverse_iterator(__first1);
 52    auto __rbegin2 = std::make_reverse_iterator(__last2);
 53    auto __rend2   = std::make_reverse_iterator(__first2);
 54    return ranges::starts_with(
 55        __rbegin1, __rend1, __rbegin2, __rend2, std::ref(__pred), std::ref(__proj1), std::ref(__proj2));
 56  }
 57
 58  template <class _Iter1, class _Sent1, class _Iter2, class _Sent2, class _Pred, class _Proj1, class _Proj2>
 59  _LIBCPP_HIDE_FROM_ABI static constexpr bool __ends_with_fn_impl(
 60      _Iter1 __first1,
 61      _Sent1 __last1,
 62      _Iter2 __first2,
 63      _Sent2 __last2,
 64      _Pred& __pred,
 65      _Proj1& __proj1,
 66      _Proj2& __proj2) {
 67    if constexpr (std::bidirectional_iterator<_Sent1> && std::bidirectional_iterator<_Sent2> &&
 68                  (!std::random_access_iterator<_Sent1>) && (!std::random_access_iterator<_Sent2>)) {
 69      return __ends_with_fn_impl_bidirectional(__first1, __last1, __first2, __last2, __pred, __proj1, __proj2);
 70
 71    } else {
 72      auto __n1 = ranges::distance(__first1, __last1);
 73      auto __n2 = ranges::distance(__first2, __last2);
 74      if (__n2 == 0)
 75        return true;
 76      if (__n2 > __n1)
 77        return false;
 78
 79      return __ends_with_fn_impl_with_offset(
 80          std::move(__first1),
 81          std::move(__last1),
 82          std::move(__first2),
 83          std::move(__last2),
 84          __pred,
 85          __proj1,
 86          __proj2,
 87          __n1 - __n2);
 88    }
 89  }
 90
 91  template <class _Iter1,
 92            class _Sent1,
 93            class _Iter2,
 94            class _Sent2,
 95            class _Pred,
 96            class _Proj1,
 97            class _Proj2,
 98            class _Offset>
 99  static _LIBCPP_HIDE_FROM_ABI constexpr bool __ends_with_fn_impl_with_offset(
100      _Iter1 __first1,
101      _Sent1 __last1,
102      _Iter2 __first2,
103      _Sent2 __last2,
104      _Pred& __pred,
105      _Proj1& __proj1,
106      _Proj2& __proj2,
107      _Offset __offset) {
108    if constexpr (std::bidirectional_iterator<_Sent1> && std::bidirectional_iterator<_Sent2> &&
109                  !std::random_access_iterator<_Sent1> && !std::random_access_iterator<_Sent2>) {
110      return __ends_with_fn_impl_bidirectional(
111          std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), __pred, __proj1, __proj2);
112
113    } else {
114      ranges::advance(__first1, __offset);
115      return ranges::equal(
116          std::move(__first1),
117          std::move(__last1),
118          std::move(__first2),
119          std::move(__last2),
120          std::ref(__pred),
121          std::ref(__proj1),
122          std::ref(__proj2));
123    }
124  }
125
126  template <input_iterator _Iter1,
127            sentinel_for<_Iter1> _Sent1,
128            input_iterator _Iter2,
129            sentinel_for<_Iter2> _Sent2,
130            class _Pred  = ranges::equal_to,
131            class _Proj1 = identity,
132            class _Proj2 = identity>
133    requires(forward_iterator<_Iter1> || sized_sentinel_for<_Sent1, _Iter1>) &&
134            (forward_iterator<_Iter2> || sized_sentinel_for<_Sent2, _Iter2>) &&
135            indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2>
136  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool operator()(
137      _Iter1 __first1,
138      _Sent1 __last1,
139      _Iter2 __first2,
140      _Sent2 __last2,
141      _Pred __pred   = {},
142      _Proj1 __proj1 = {},
143      _Proj2 __proj2 = {}) const {
144    return __ends_with_fn_impl(
145        std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), __pred, __proj1, __proj2);
146  }
147
148  template <input_range _Range1,
149            input_range _Range2,
150            class _Pred  = ranges::equal_to,
151            class _Proj1 = identity,
152            class _Proj2 = identity>
153    requires(forward_range<_Range1> || sized_range<_Range1>) && (forward_range<_Range2> || sized_range<_Range2>) &&
154            indirectly_comparable<iterator_t<_Range1>, iterator_t<_Range2>, _Pred, _Proj1, _Proj2>
155  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool operator()(
156      _Range1&& __range1, _Range2&& __range2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const {
157    if constexpr (sized_range<_Range1> && sized_range<_Range2>) {
158      auto __n1 = ranges::size(__range1);
159      auto __n2 = ranges::size(__range2);
160      if (__n2 == 0)
161        return true;
162      if (__n2 > __n1)
163        return false;
164      auto __offset = __n1 - __n2;
165
166      return __ends_with_fn_impl_with_offset(
167          ranges::begin(__range1),
168          ranges::end(__range1),
169          ranges::begin(__range2),
170          ranges::end(__range2),
171          __pred,
172          __proj1,
173          __proj2,
174          __offset);
175
176    } else {
177      return __ends_with_fn_impl(
178          ranges::begin(__range1),
179          ranges::end(__range1),
180          ranges::begin(__range2),
181          ranges::end(__range2),
182          __pred,
183          __proj1,
184          __proj2);
185    }
186  }
187};
188
189inline namespace __cpo {
190inline constexpr auto ends_with = __ends_with{};
191} // namespace __cpo
192} // namespace ranges
193
194_LIBCPP_END_NAMESPACE_STD
195
196#endif // _LIBCPP_STD_VER >= 23
197
198_LIBCPP_POP_MACROS
199
200#endif // _LIBCPP___ALGORITHM_RANGES_ENDS_WITH_H