join_view.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  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_JOIN_VIEW_H
  10. #define _LIBCPP___RANGES_JOIN_VIEW_H
  11. #include <__concepts/constructible.h>
  12. #include <__concepts/convertible_to.h>
  13. #include <__concepts/copyable.h>
  14. #include <__concepts/derived_from.h>
  15. #include <__concepts/equality_comparable.h>
  16. #include <__config>
  17. #include <__iterator/concepts.h>
  18. #include <__iterator/iter_move.h>
  19. #include <__iterator/iter_swap.h>
  20. #include <__iterator/iterator_traits.h>
  21. #include <__iterator/iterator_with_data.h>
  22. #include <__iterator/segmented_iterator.h>
  23. #include <__ranges/access.h>
  24. #include <__ranges/all.h>
  25. #include <__ranges/concepts.h>
  26. #include <__ranges/empty.h>
  27. #include <__ranges/non_propagating_cache.h>
  28. #include <__ranges/range_adaptor.h>
  29. #include <__ranges/view_interface.h>
  30. #include <__type_traits/maybe_const.h>
  31. #include <__utility/forward.h>
  32. #include <optional>
  33. #include <type_traits>
  34. #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
  35. # pragma GCC system_header
  36. #endif
  37. _LIBCPP_BEGIN_NAMESPACE_STD
  38. // Note: `join_view` is still marked experimental because there is an ABI-breaking change that affects `join_view` in
  39. // the pipeline (https://isocpp.org/files/papers/D2770R0.html).
  40. // TODO: make `join_view` non-experimental once D2770 is implemented.
  41. #if _LIBCPP_STD_VER > 17
  42. namespace ranges {
  43. template<class>
  44. struct __join_view_iterator_category {};
  45. template<class _View>
  46. requires is_reference_v<range_reference_t<_View>> &&
  47. forward_range<_View> &&
  48. forward_range<range_reference_t<_View>>
  49. struct __join_view_iterator_category<_View> {
  50. using _OuterC = typename iterator_traits<iterator_t<_View>>::iterator_category;
  51. using _InnerC = typename iterator_traits<iterator_t<range_reference_t<_View>>>::iterator_category;
  52. using iterator_category = _If<
  53. derived_from<_OuterC, bidirectional_iterator_tag> && derived_from<_InnerC, bidirectional_iterator_tag> &&
  54. common_range<range_reference_t<_View>>,
  55. bidirectional_iterator_tag,
  56. _If<
  57. derived_from<_OuterC, forward_iterator_tag> && derived_from<_InnerC, forward_iterator_tag>,
  58. forward_iterator_tag,
  59. input_iterator_tag
  60. >
  61. >;
  62. };
  63. template<input_range _View>
  64. requires view<_View> && input_range<range_reference_t<_View>>
  65. class join_view
  66. : public view_interface<join_view<_View>> {
  67. private:
  68. using _InnerRange = range_reference_t<_View>;
  69. template<bool> struct __iterator;
  70. template<bool> struct __sentinel;
  71. template <class>
  72. friend struct std::__segmented_iterator_traits;
  73. static constexpr bool _UseCache = !is_reference_v<_InnerRange>;
  74. using _Cache = _If<_UseCache, __non_propagating_cache<remove_cvref_t<_InnerRange>>, __empty_cache>;
  75. _LIBCPP_NO_UNIQUE_ADDRESS _Cache __cache_;
  76. _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
  77. public:
  78. _LIBCPP_HIDE_FROM_ABI
  79. join_view() requires default_initializable<_View> = default;
  80. _LIBCPP_HIDE_FROM_ABI
  81. constexpr explicit join_view(_View __base)
  82. : __base_(std::move(__base)) {}
  83. _LIBCPP_HIDE_FROM_ABI
  84. constexpr _View base() const& requires copy_constructible<_View> { return __base_; }
  85. _LIBCPP_HIDE_FROM_ABI
  86. constexpr _View base() && { return std::move(__base_); }
  87. _LIBCPP_HIDE_FROM_ABI
  88. constexpr auto begin() {
  89. constexpr bool __use_const = __simple_view<_View> &&
  90. is_reference_v<range_reference_t<_View>>;
  91. return __iterator<__use_const>{*this, ranges::begin(__base_)};
  92. }
  93. template<class _V2 = _View>
  94. _LIBCPP_HIDE_FROM_ABI
  95. constexpr auto begin() const
  96. requires input_range<const _V2> &&
  97. is_reference_v<range_reference_t<const _V2>>
  98. {
  99. return __iterator<true>{*this, ranges::begin(__base_)};
  100. }
  101. _LIBCPP_HIDE_FROM_ABI
  102. constexpr auto end() {
  103. if constexpr (forward_range<_View> &&
  104. is_reference_v<_InnerRange> &&
  105. forward_range<_InnerRange> &&
  106. common_range<_View> &&
  107. common_range<_InnerRange>)
  108. return __iterator<__simple_view<_View>>{*this, ranges::end(__base_)};
  109. else
  110. return __sentinel<__simple_view<_View>>{*this};
  111. }
  112. template<class _V2 = _View>
  113. _LIBCPP_HIDE_FROM_ABI
  114. constexpr auto end() const
  115. requires input_range<const _V2> &&
  116. is_reference_v<range_reference_t<const _V2>>
  117. {
  118. using _ConstInnerRange = range_reference_t<const _View>;
  119. if constexpr (forward_range<const _View> &&
  120. is_reference_v<_ConstInnerRange> &&
  121. forward_range<_ConstInnerRange> &&
  122. common_range<const _View> &&
  123. common_range<_ConstInnerRange>) {
  124. return __iterator<true>{*this, ranges::end(__base_)};
  125. } else {
  126. return __sentinel<true>{*this};
  127. }
  128. }
  129. };
  130. template<input_range _View>
  131. requires view<_View> && input_range<range_reference_t<_View>>
  132. template<bool _Const>
  133. struct join_view<_View>::__sentinel {
  134. template<bool>
  135. friend struct __sentinel;
  136. private:
  137. using _Parent = __maybe_const<_Const, join_view<_View>>;
  138. using _Base = __maybe_const<_Const, _View>;
  139. sentinel_t<_Base> __end_ = sentinel_t<_Base>();
  140. public:
  141. _LIBCPP_HIDE_FROM_ABI
  142. __sentinel() = default;
  143. _LIBCPP_HIDE_FROM_ABI
  144. constexpr explicit __sentinel(_Parent& __parent)
  145. : __end_(ranges::end(__parent.__base_)) {}
  146. _LIBCPP_HIDE_FROM_ABI
  147. constexpr __sentinel(__sentinel<!_Const> __s)
  148. requires _Const && convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
  149. : __end_(std::move(__s.__end_)) {}
  150. template<bool _OtherConst>
  151. requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>>
  152. _LIBCPP_HIDE_FROM_ABI
  153. friend constexpr bool operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
  154. return __x.__outer_ == __y.__end_;
  155. }
  156. };
  157. // https://reviews.llvm.org/D142811#inline-1383022
  158. // To simplify the segmented iterator traits specialization,
  159. // make the iterator `final`
  160. template<input_range _View>
  161. requires view<_View> && input_range<range_reference_t<_View>>
  162. template<bool _Const>
  163. struct join_view<_View>::__iterator final
  164. : public __join_view_iterator_category<__maybe_const<_Const, _View>> {
  165. template<bool>
  166. friend struct __iterator;
  167. template <class>
  168. friend struct std::__segmented_iterator_traits;
  169. static constexpr bool __is_join_view_iterator = true;
  170. private:
  171. using _Parent = __maybe_const<_Const, join_view<_View>>;
  172. using _Base = __maybe_const<_Const, _View>;
  173. using _Outer = iterator_t<_Base>;
  174. using _Inner = iterator_t<range_reference_t<_Base>>;
  175. using _InnerRange = range_reference_t<_View>;
  176. static constexpr bool __ref_is_glvalue = is_reference_v<range_reference_t<_Base>>;
  177. public:
  178. _Outer __outer_ = _Outer();
  179. private:
  180. optional<_Inner> __inner_;
  181. _Parent *__parent_ = nullptr;
  182. _LIBCPP_HIDE_FROM_ABI
  183. constexpr void __satisfy() {
  184. for (; __outer_ != ranges::end(__parent_->__base_); ++__outer_) {
  185. auto&& __inner = [&]() -> auto&& {
  186. if constexpr (__ref_is_glvalue)
  187. return *__outer_;
  188. else
  189. return __parent_->__cache_.__emplace_from([&]() -> decltype(auto) { return *__outer_; });
  190. }();
  191. __inner_ = ranges::begin(__inner);
  192. if (*__inner_ != ranges::end(__inner))
  193. return;
  194. }
  195. if constexpr (__ref_is_glvalue)
  196. __inner_.reset();
  197. }
  198. _LIBCPP_HIDE_FROM_ABI constexpr __iterator(_Parent* __parent, _Outer __outer, _Inner __inner)
  199. : __outer_(std::move(__outer)), __inner_(std::move(__inner)), __parent_(__parent) {}
  200. public:
  201. using iterator_concept = _If<
  202. __ref_is_glvalue && bidirectional_range<_Base> && bidirectional_range<range_reference_t<_Base>> &&
  203. common_range<range_reference_t<_Base>>,
  204. bidirectional_iterator_tag,
  205. _If<
  206. __ref_is_glvalue && forward_range<_Base> && forward_range<range_reference_t<_Base>>,
  207. forward_iterator_tag,
  208. input_iterator_tag
  209. >
  210. >;
  211. using value_type = range_value_t<range_reference_t<_Base>>;
  212. using difference_type = common_type_t<
  213. range_difference_t<_Base>, range_difference_t<range_reference_t<_Base>>>;
  214. _LIBCPP_HIDE_FROM_ABI
  215. __iterator() requires default_initializable<_Outer> = default;
  216. _LIBCPP_HIDE_FROM_ABI
  217. constexpr __iterator(_Parent& __parent, _Outer __outer)
  218. : __outer_(std::move(__outer))
  219. , __parent_(std::addressof(__parent)) {
  220. __satisfy();
  221. }
  222. _LIBCPP_HIDE_FROM_ABI
  223. constexpr __iterator(__iterator<!_Const> __i)
  224. requires _Const &&
  225. convertible_to<iterator_t<_View>, _Outer> &&
  226. convertible_to<iterator_t<_InnerRange>, _Inner>
  227. : __outer_(std::move(__i.__outer_))
  228. , __inner_(std::move(__i.__inner_))
  229. , __parent_(__i.__parent_) {}
  230. _LIBCPP_HIDE_FROM_ABI
  231. constexpr decltype(auto) operator*() const {
  232. return **__inner_;
  233. }
  234. _LIBCPP_HIDE_FROM_ABI
  235. constexpr _Inner operator->() const
  236. requires __has_arrow<_Inner> && copyable<_Inner>
  237. {
  238. return *__inner_;
  239. }
  240. _LIBCPP_HIDE_FROM_ABI
  241. constexpr __iterator& operator++() {
  242. auto&& __inner = [&]() -> auto&& {
  243. if constexpr (__ref_is_glvalue)
  244. return *__outer_;
  245. else
  246. return *__parent_->__cache_;
  247. }();
  248. if (++*__inner_ == ranges::end(__inner)) {
  249. ++__outer_;
  250. __satisfy();
  251. }
  252. return *this;
  253. }
  254. _LIBCPP_HIDE_FROM_ABI
  255. constexpr void operator++(int) {
  256. ++*this;
  257. }
  258. _LIBCPP_HIDE_FROM_ABI
  259. constexpr __iterator operator++(int)
  260. requires __ref_is_glvalue &&
  261. forward_range<_Base> &&
  262. forward_range<range_reference_t<_Base>>
  263. {
  264. auto __tmp = *this;
  265. ++*this;
  266. return __tmp;
  267. }
  268. _LIBCPP_HIDE_FROM_ABI
  269. constexpr __iterator& operator--()
  270. requires __ref_is_glvalue &&
  271. bidirectional_range<_Base> &&
  272. bidirectional_range<range_reference_t<_Base>> &&
  273. common_range<range_reference_t<_Base>>
  274. {
  275. if (__outer_ == ranges::end(__parent_->__base_))
  276. __inner_ = ranges::end(*--__outer_);
  277. // Skip empty inner ranges when going backwards.
  278. while (*__inner_ == ranges::begin(*__outer_)) {
  279. __inner_ = ranges::end(*--__outer_);
  280. }
  281. --*__inner_;
  282. return *this;
  283. }
  284. _LIBCPP_HIDE_FROM_ABI
  285. constexpr __iterator operator--(int)
  286. requires __ref_is_glvalue &&
  287. bidirectional_range<_Base> &&
  288. bidirectional_range<range_reference_t<_Base>> &&
  289. common_range<range_reference_t<_Base>>
  290. {
  291. auto __tmp = *this;
  292. --*this;
  293. return __tmp;
  294. }
  295. _LIBCPP_HIDE_FROM_ABI
  296. friend constexpr bool operator==(const __iterator& __x, const __iterator& __y)
  297. requires __ref_is_glvalue &&
  298. equality_comparable<iterator_t<_Base>> &&
  299. equality_comparable<iterator_t<range_reference_t<_Base>>>
  300. {
  301. return __x.__outer_ == __y.__outer_ && __x.__inner_ == __y.__inner_;
  302. }
  303. _LIBCPP_HIDE_FROM_ABI
  304. friend constexpr decltype(auto) iter_move(const __iterator& __i)
  305. noexcept(noexcept(ranges::iter_move(*__i.__inner_)))
  306. {
  307. return ranges::iter_move(*__i.__inner_);
  308. }
  309. _LIBCPP_HIDE_FROM_ABI
  310. friend constexpr void iter_swap(const __iterator& __x, const __iterator& __y)
  311. noexcept(noexcept(ranges::iter_swap(*__x.__inner_, *__y.__inner_)))
  312. requires indirectly_swappable<_Inner>
  313. {
  314. return ranges::iter_swap(*__x.__inner_, *__y.__inner_);
  315. }
  316. };
  317. template<class _Range>
  318. explicit join_view(_Range&&) -> join_view<views::all_t<_Range>>;
  319. namespace views {
  320. namespace __join_view {
  321. struct __fn : __range_adaptor_closure<__fn> {
  322. template<class _Range>
  323. [[nodiscard]] _LIBCPP_HIDE_FROM_ABI
  324. constexpr auto operator()(_Range&& __range) const
  325. noexcept(noexcept(join_view<all_t<_Range&&>>(std::forward<_Range>(__range))))
  326. -> decltype( join_view<all_t<_Range&&>>(std::forward<_Range>(__range)))
  327. { return join_view<all_t<_Range&&>>(std::forward<_Range>(__range)); }
  328. };
  329. } // namespace __join_view
  330. inline namespace __cpo {
  331. inline constexpr auto join = __join_view::__fn{};
  332. } // namespace __cpo
  333. } // namespace views
  334. } // namespace ranges
  335. template <class _JoinViewIterator>
  336. requires(_JoinViewIterator::__is_join_view_iterator &&
  337. ranges::common_range<typename _JoinViewIterator::_Parent> &&
  338. __is_cpp17_random_access_iterator<typename _JoinViewIterator::_Outer>::value &&
  339. __is_cpp17_random_access_iterator<typename _JoinViewIterator::_Inner>::value)
  340. struct __segmented_iterator_traits<_JoinViewIterator> {
  341. using __segment_iterator =
  342. _LIBCPP_NODEBUG __iterator_with_data<typename _JoinViewIterator::_Outer, typename _JoinViewIterator::_Parent*>;
  343. using __local_iterator = typename _JoinViewIterator::_Inner;
  344. // TODO: Would it make sense to enable the optimization for other iterator types?
  345. static constexpr _LIBCPP_HIDE_FROM_ABI __segment_iterator __segment(_JoinViewIterator __iter) {
  346. if (ranges::empty(__iter.__parent_->__base_))
  347. return {};
  348. if (!__iter.__inner_.has_value())
  349. return __segment_iterator(--__iter.__outer_, __iter.__parent_);
  350. return __segment_iterator(__iter.__outer_, __iter.__parent_);
  351. }
  352. static constexpr _LIBCPP_HIDE_FROM_ABI __local_iterator __local(_JoinViewIterator __iter) {
  353. if (ranges::empty(__iter.__parent_->__base_))
  354. return {};
  355. if (!__iter.__inner_.has_value())
  356. return ranges::end(*--__iter.__outer_);
  357. return *__iter.__inner_;
  358. }
  359. static constexpr _LIBCPP_HIDE_FROM_ABI __local_iterator __begin(__segment_iterator __iter) {
  360. return ranges::begin(*__iter.__get_iter());
  361. }
  362. static constexpr _LIBCPP_HIDE_FROM_ABI __local_iterator __end(__segment_iterator __iter) {
  363. return ranges::end(*__iter.__get_iter());
  364. }
  365. static constexpr _LIBCPP_HIDE_FROM_ABI _JoinViewIterator
  366. __compose(__segment_iterator __seg_iter, __local_iterator __local_iter) {
  367. return _JoinViewIterator(
  368. std::move(__seg_iter).__get_data(), std::move(__seg_iter).__get_iter(), std::move(__local_iter));
  369. }
  370. };
  371. #endif // #if _LIBCPP_STD_VER > 17 && defined(_LIBCPP_ENABLE_EXPERIMENTAL)
  372. _LIBCPP_END_NAMESPACE_STD
  373. #endif // _LIBCPP___RANGES_JOIN_VIEW_H