take_while_view.h 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. // -*- C++ -*-
  2. //===----------------------------------------------------------------------===//
  3. //
  4. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  5. // See https://llvm.org/LICENSE.txt for license information.
  6. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  7. //
  8. //===----------------------------------------------------------------------===//
  9. #ifndef _LIBCPP___RANGES_TAKE_WHILE_VIEW_H
  10. #define _LIBCPP___RANGES_TAKE_WHILE_VIEW_H
  11. #include <__concepts/constructible.h>
  12. #include <__concepts/convertible_to.h>
  13. #include <__config>
  14. #include <__functional/bind_back.h>
  15. #include <__functional/invoke.h>
  16. #include <__iterator/concepts.h>
  17. #include <__memory/addressof.h>
  18. #include <__ranges/access.h>
  19. #include <__ranges/all.h>
  20. #include <__ranges/concepts.h>
  21. #include <__ranges/copyable_box.h>
  22. #include <__ranges/range_adaptor.h>
  23. #include <__ranges/view_interface.h>
  24. #include <__type_traits/decay.h>
  25. #include <__type_traits/is_nothrow_constructible.h>
  26. #include <__type_traits/is_object.h>
  27. #include <__type_traits/maybe_const.h>
  28. #include <__utility/forward.h>
  29. #include <__utility/in_place.h>
  30. #include <__utility/move.h>
  31. #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
  32. # pragma GCC system_header
  33. #endif
  34. _LIBCPP_BEGIN_NAMESPACE_STD
  35. #if _LIBCPP_STD_VER >= 20
  36. namespace ranges {
  37. // The spec uses the unnamed requirement inside the `begin` and `end` member functions:
  38. // constexpr auto begin() const
  39. // requires range<const V> && indirect_unary_predicate<const Pred, iterator_t<const V>>
  40. // However, due to a clang-14 and clang-15 bug, the above produces a hard error when `const V` is not a range.
  41. // The workaround is to create a named concept and use the concept instead.
  42. // As of take_while_view is implemented, the clang-trunk has already fixed the bug.
  43. // It is OK to remove the workaround once our CI no longer uses clang-14, clang-15 based compilers,
  44. // because we don't actually expect a lot of vendors to ship a new libc++ with an old clang.
  45. template <class _View, class _Pred>
  46. concept __take_while_const_is_range =
  47. range<const _View> && indirect_unary_predicate<const _Pred, iterator_t<const _View>>;
  48. template <view _View, class _Pred>
  49. requires input_range<_View> && is_object_v<_Pred> && indirect_unary_predicate<const _Pred, iterator_t<_View>>
  50. class take_while_view : public view_interface<take_while_view<_View, _Pred>> {
  51. template <bool>
  52. class __sentinel;
  53. _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
  54. _LIBCPP_NO_UNIQUE_ADDRESS __copyable_box<_Pred> __pred_;
  55. public:
  56. _LIBCPP_HIDE_FROM_ABI take_while_view()
  57. requires default_initializable<_View> && default_initializable<_Pred>
  58. = default;
  59. _LIBCPP_HIDE_FROM_ABI constexpr take_while_view(_View __base, _Pred __pred)
  60. : __base_(std::move(__base)), __pred_(std::in_place, std::move(__pred)) {}
  61. _LIBCPP_HIDE_FROM_ABI constexpr _View base() const&
  62. requires copy_constructible<_View>
  63. {
  64. return __base_;
  65. }
  66. _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); }
  67. _LIBCPP_HIDE_FROM_ABI constexpr const _Pred& pred() const { return *__pred_; }
  68. _LIBCPP_HIDE_FROM_ABI constexpr auto begin()
  69. requires(!__simple_view<_View>)
  70. {
  71. return ranges::begin(__base_);
  72. }
  73. _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const
  74. requires __take_while_const_is_range<_View, _Pred>
  75. {
  76. return ranges::begin(__base_);
  77. }
  78. _LIBCPP_HIDE_FROM_ABI constexpr auto end()
  79. requires(!__simple_view<_View>)
  80. {
  81. return __sentinel</*_Const=*/false>(ranges::end(__base_), std::addressof(*__pred_));
  82. }
  83. _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
  84. requires __take_while_const_is_range<_View, _Pred>
  85. {
  86. return __sentinel</*_Const=*/true>(ranges::end(__base_), std::addressof(*__pred_));
  87. }
  88. };
  89. template <class _Range, class _Pred>
  90. take_while_view(_Range&&, _Pred) -> take_while_view<views::all_t<_Range>, _Pred>;
  91. template <view _View, class _Pred>
  92. requires input_range<_View> && is_object_v<_Pred> && indirect_unary_predicate<const _Pred, iterator_t<_View>>
  93. template <bool _Const>
  94. class take_while_view<_View, _Pred>::__sentinel {
  95. using _Base = __maybe_const<_Const, _View>;
  96. sentinel_t<_Base> __end_ = sentinel_t<_Base>();
  97. const _Pred* __pred_ = nullptr;
  98. friend class __sentinel<!_Const>;
  99. public:
  100. _LIBCPP_HIDE_FROM_ABI __sentinel() = default;
  101. _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(sentinel_t<_Base> __end, const _Pred* __pred)
  102. : __end_(std::move(__end)), __pred_(__pred) {}
  103. _LIBCPP_HIDE_FROM_ABI constexpr __sentinel(__sentinel<!_Const> __s)
  104. requires _Const && convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
  105. : __end_(std::move(__s.__end_)), __pred_(__s.__pred_) {}
  106. _LIBCPP_HIDE_FROM_ABI constexpr sentinel_t<_Base> base() const { return __end_; }
  107. _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const iterator_t<_Base>& __x, const __sentinel& __y) {
  108. return __x == __y.__end_ || !std::invoke(*__y.__pred_, *__x);
  109. }
  110. template <bool _OtherConst = !_Const>
  111. requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
  112. _LIBCPP_HIDE_FROM_ABI friend constexpr bool
  113. operator==(const iterator_t<__maybe_const<_OtherConst, _View>>& __x, const __sentinel& __y) {
  114. return __x == __y.__end_ || !std::invoke(*__y.__pred_, *__x);
  115. }
  116. };
  117. namespace views {
  118. namespace __take_while {
  119. struct __fn {
  120. template <class _Range, class _Pred>
  121. [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range, _Pred&& __pred) const
  122. noexcept(noexcept(/**/ take_while_view(std::forward<_Range>(__range), std::forward<_Pred>(__pred))))
  123. -> decltype(/*--*/ take_while_view(std::forward<_Range>(__range), std::forward<_Pred>(__pred))) {
  124. return /*-------------*/ take_while_view(std::forward<_Range>(__range), std::forward<_Pred>(__pred));
  125. }
  126. template <class _Pred>
  127. requires constructible_from<decay_t<_Pred>, _Pred>
  128. [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Pred&& __pred) const
  129. noexcept(is_nothrow_constructible_v<decay_t<_Pred>, _Pred>) {
  130. return __range_adaptor_closure_t(std::__bind_back(*this, std::forward<_Pred>(__pred)));
  131. }
  132. };
  133. } // namespace __take_while
  134. inline namespace __cpo {
  135. inline constexpr auto take_while = __take_while::__fn{};
  136. } // namespace __cpo
  137. } // namespace views
  138. } // namespace ranges
  139. #endif // _LIBCPP_STD_VER >= 20
  140. _LIBCPP_END_NAMESPACE_STD
  141. #endif // _LIBCPP___RANGES_TAKE_WHILE_VIEW_H