29template <
class R,
class P>
30concept compatible_joinable_ranges =
31 std::common_with<std::ranges::range_value_t<R>, std::ranges::range_value_t<P>>
32 && std::common_reference_with<std::ranges::range_reference_t<R>, std::ranges::range_reference_t<P>>
33 && std::common_reference_with<std::ranges::range_rvalue_reference_t<R>, std::ranges::range_rvalue_reference_t<P>>;
36concept bidirectional_common = std::ranges::bidirectional_range<R> && std::ranges::common_range<R>;
39template <
typename InnerRng>
44template <
typename InnerRng>
45 requires std::is_reference_v<InnerRng>
46struct cache_helper<InnerRng>
50template <
typename InnerRng>
51 requires (!std::is_reference_v<InnerRng>)
52struct cache_helper<InnerRng>
54 non_propagating_cache<std::remove_cv_t<InnerRng>> inner_;
59namespace seqan3::detail
62template <std::ranges::input_range V, std::ranges::forward_range Pattern>
63 requires std::ranges::view<V> && std::ranges::input_range<std::ranges::range_reference_t<V>>
64 && std::ranges::view<Pattern>
65 && join_with::compatible_joinable_ranges<std::ranges::range_reference_t<V>, Pattern>
67 public std::ranges::view_interface<join_with_view<V, Pattern>>,
68 private join_with::cache_helper<std::ranges::range_reference_t<V>>
70 using InnerRng = std::ranges::range_reference_t<V>;
84 requires std::default_initializable<V> &&
std::default_initializable<Pattern>
87 constexpr join_with_view(V base, Pattern pattern) : base_(
std::move(base)), pattern_(
std::move(pattern))
90 template <std::ranges::input_range R>
91 requires std::constructible_from<V, std::ranges::views::all_t<R>>
92 && std::constructible_from<Pattern, std::ranges::single_view<std::ranges::range_value_t<InnerRng>>>
93 constexpr join_with_view(R && r, std::ranges::range_value_t<InnerRng> e) :
98 constexpr V base() const &
99 requires
std::copy_constructible<V>
104 constexpr V base() &&
106 return std::move(base_);
109 constexpr auto begin()
115 constexpr bool use_const =
116 view_helper::simple_view<V> && std::is_reference_v<InnerRng> && view_helper::simple_view<Pattern>;
120 constexpr auto begin() const
121 requires
std::ranges::input_range<V const> &&
std::ranges::forward_range<Pattern const>
122 &&
std::is_reference_v<
std::ranges::range_reference_t<V const>>
128#if defined(__GNUC__) && (__GNUC__ == 10)
130 && std::ranges::forward_range<InnerRng> && std::ranges::common_range<V>
131 && std::ranges::common_range<InnerRng>,
132 iterator<view_helper::simple_view<V> && view_helper::simple_view<Pattern>>,
133 sentinel<view_helper::simple_view<V> && view_helper::simple_view<Pattern>>>
136 constexpr bool is_simple = view_helper::simple_view<V> && view_helper::simple_view<Pattern>;
137 if constexpr (std::ranges::forward_range<V> && std::is_reference_v<InnerRng>
138 && std::ranges::forward_range<InnerRng> && std::ranges::common_range<V>
139 && std::ranges::common_range<InnerRng>)
140 return iterator<is_simple>{*
this, std::ranges::end(base_)};
142 return sentinel<is_simple>{*
this};
145 constexpr auto end() const
146 requires
std::ranges::input_range<V const> &&
std::ranges::forward_range<Pattern const>
147 &&
std::is_reference_v<
std::ranges::range_reference_t<V const>>
149 using InnerConstRng = std::ranges::range_reference_t<V const>;
150 if constexpr (std::ranges::forward_range<V const> && std::ranges::forward_range<InnerConstRng>
151 && std::ranges::common_range<V const> && std::ranges::common_range<InnerConstRng>)
152 return iterator<true>{*
this, std::ranges::end(base_)};
154 return sentinel<true>{*
this};
158template <
class R,
class P>
159join_with_view(R &&, P &&) -> join_with_view<seqan3::detail::all_t<R>, seqan3::detail::all_t<P>>;
161template <std::ranges::input_range R>
162join_with_view(R &&, std::ranges::range_value_t<std::ranges::range_reference_t<R>>)
163 -> join_with_view<seqan3::detail::all_t<R>,
164 std::ranges::single_view<std::ranges::range_value_t<std::ranges::range_reference_t<R>>>>;
173template <
bool Const,
typename V,
typename Pattern>
176 using Parent = view_helper::maybe_const<Const, join_with_view<V, Pattern>>;
177 using Base = view_helper::maybe_const<Const, V>;
178 using InnerBase = std::ranges::range_reference_t<Base>;
179 using PatternBase = view_helper::maybe_const<Const, Pattern>;
181 using OuterIter = std::ranges::iterator_t<Base>;
182 using InnerIter = std::ranges::iterator_t<InnerBase>;
183 using PatternIter = std::ranges::iterator_t<PatternBase>;
185 static constexpr bool ref_is_glvalue = std::is_reference_v<InnerBase>;
188template <
bool Const,
typename V,
typename Pattern,
bool ref_is_glvalue>
189struct iterator_category_t;
192template <
bool Const,
typename V,
typename Pattern>
193struct iterator_category_t<Const, V, Pattern, true>
195 using Parent = helper<Const, V, Pattern>::Parent;
196 using Base = helper<Const, V, Pattern>::Base;
197 using InnerBase = helper<Const, V, Pattern>::InnerBase;
198 using PatternBase = helper<Const, V, Pattern>::PatternBase;
200 using OuterIter = helper<Const, V, Pattern>::OuterIter;
201 using InnerIter = helper<Const, V, Pattern>::InnerIter;
202 using PatternIter = helper<Const, V, Pattern>::PatternIter;
215 && std::ranges::common_range<InnerBase> && std::ranges::common_range<PatternBase>,
228template <
bool Const,
typename V,
typename Pattern>
229struct iterator_category_t<Const, V, Pattern, false>
234namespace seqan3::detail
237template <std::ranges::input_range V, std::ranges::forward_range Pattern>
238 requires std::ranges::view<V> && std::ranges::input_range<std::ranges::range_reference_t<V>>
239 && std::ranges::view<Pattern>
240 && join_with::compatible_joinable_ranges<std::ranges::range_reference_t<V>, Pattern>
242class join_with_view<V, Pattern>::iterator :
243 public join_with::iterator_category_t<Const, V, Pattern, join_with::helper<Const, V, Pattern>::ref_is_glvalue>
245 using helper_t = join_with::helper<Const, V, Pattern>;
246 using Parent = helper_t::Parent;
247 using Base = helper_t::Base;
248 using InnerBase = helper_t::InnerBase;
249 using PatternBase = helper_t::PatternBase;
251 using OuterIter = helper_t::OuterIter;
252 using InnerIter = helper_t::InnerIter;
253 using PatternIter = helper_t::PatternIter;
255 static constexpr bool ref_is_glvalue = helper_t::ref_is_glvalue;
257 friend class join_with_view<V, Pattern>;
259 Parent * parent_{
nullptr};
262 OuterIter outer_it_{};
267 constexpr iterator(Parent & parent, std::ranges::iterator_t<Base> outer) :
271 if (outer_it_ != std::ranges::end(parent_->base_))
273 auto && inner = update_inner(outer_it_);
279 constexpr auto && update_inner(OuterIter
const & x)
281 if constexpr (ref_is_glvalue)
284 return parent_->inner_.emplace_deref(x);
287 constexpr auto && get_inner(OuterIter
const & x)
289 if constexpr (ref_is_glvalue)
292 return *parent_->inner_;
297 constexpr void satisfy()
301 if (inner_it_.index() == 0)
303 if (std::get<0>(inner_it_) != std::ranges::end(parent_->pattern_))
305 auto && inner = update_inner(outer_it_);
310 auto && inner = get_inner(outer_it_);
311 if (std::get<1>(inner_it_) != std::ranges::end(inner))
313 if (++outer_it_ == std::ranges::end(parent_->base_))
315 if constexpr (ref_is_glvalue)
316 inner_it_.template emplace<0>();
329 && join_with::bidirectional_common<PatternBase>,
341 requires std::default_initializable<OuterIter>
344 constexpr iterator(iterator<!Const> i)
345 requires Const &&
std::convertible_to<
std::ranges::iterator_t<V>, OuterIter>
346 &&
std::convertible_to<
std::ranges::iterator_t<InnerRng>, InnerIter>
347 &&
std::convertible_to<
std::ranges::iterator_t<Pattern>, PatternIter>
348 : outer_it_(
std::move(i.outer_it_)), parent_(i.parent_)
350 if (i.inner_it_.index() == 0)
351 inner_it_.template emplace<0>(std::get<0>(std::move(i.inner_it_)));
353 inner_it_.template emplace<1>(std::get<1>(std::move(i.inner_it_)));
356 constexpr decltype(
auto)
operator*()
const
360 [](
auto & it) -> reference
367 constexpr iterator & operator++()
379 constexpr void operator++(
int)
384 constexpr iterator operator++(
int)
385 requires ref_is_glvalue && std::forward_iterator<OuterIter> && std::forward_iterator<InnerIter>
387 iterator tmp = *
this;
392 constexpr iterator & operator--()
393 requires ref_is_glvalue &&
std::ranges::bidirectional_range<Base> &&
join_with::bidirectional_common<InnerBase>
394 &&
join_with::bidirectional_common<PatternBase>
396 if (outer_it_ == std::ranges::end(parent_->base_))
398 auto && inner = *--outer_it_;
399 inner_it_.template emplace<1>(std::ranges::end(inner));
405 if (inner_it_.index() == 0)
407 auto & it = std::get<0>(inner_it_);
410 auto && inner = *--outer_it_;
411 inner_it_.template emplace<1>(std::ranges::end(inner));
420 auto & it = std::get<1>(inner_it_);
421 auto && inner = *outer_it_;
424 inner_it_.template emplace<0>(std::ranges::end(parent_->pattern_));
442 constexpr iterator operator--(
int)
443 requires ref_is_glvalue && std::ranges::bidirectional_range<Base> && join_with::bidirectional_common<InnerBase>
444 && join_with::bidirectional_common<PatternBase>
446 iterator tmp = *
this;
451 friend constexpr bool operator==(iterator
const & x, iterator
const & y)
452 requires ref_is_glvalue && std::equality_comparable<OuterIter> && std::equality_comparable<InnerIter>
454 return x.outer_it_ == y.outer_it_ && x.inner_it_ == y.inner_it_;
457 friend constexpr decltype(
auto) iter_move(iterator
const & x)
459 using rvalue_reference =
461 return std::visit<rvalue_reference>(std::ranges::iter_move, x.inner_it_);
464 friend constexpr void iter_swap(iterator
const & x, iterator
const & y)
465 requires std::indirectly_swappable<InnerIter, PatternIter>
467 std::visit(std::ranges::iter_swap, x.inner_it_, y.inner_it_);
471template <std::ranges::input_range V, std::ranges::forward_range Pattern>
472 requires std::ranges::view<V> && std::ranges::input_range<std::ranges::range_reference_t<V>>
473 && std::ranges::view<Pattern>
474 && join_with::compatible_joinable_ranges<std::ranges::range_reference_t<V>, Pattern>
476class join_with_view<V, Pattern>::sentinel
478 using Parent = view_helper::maybe_const<Const, join_with_view>;
479 using Base = view_helper::maybe_const<Const, V>;
480 std::ranges::sentinel_t<Base> end_ = std::ranges::sentinel_t<Base>();
482 friend class join_with_view<V, Pattern>;
484 constexpr explicit sentinel(Parent & parent) : end_(
std::ranges::
end(parent.base_))
488 sentinel() =
default;
489 constexpr sentinel(sentinel<!Const> s)
490 requires Const && std::convertible_to<std::ranges::sentinel_t<V>, std::ranges::sentinel_t<Base>>
491 : end_(std::move(s.end_))
494 template <
bool OtherConst>
495 requires std::sentinel_for<std::ranges::sentinel_t<Base>,
496 std::ranges::iterator_t<view_helper::maybe_const<OtherConst, V>>>
497 friend constexpr bool operator==(iterator<OtherConst>
const & x, sentinel
const & y)
499 return x.outer_it_ == y.end_;
505 template <
typename Pattern>
506 constexpr auto operator()(Pattern && pattern)
const
508 return seqan3::detail::adaptor_from_functor{*
this, std::forward<Pattern>(pattern)};
511 template <std::ranges::range urng_t,
typename Pattern>
512 constexpr auto operator()(urng_t && urange, Pattern && pattern)
const
514 return join_with_view{std::forward<urng_t>(urange), std::forward<Pattern>(pattern)};
531inline constexpr auto join_with = seqan3::detail::join_with_fn{};
Provides seqan3::detail::adaptor_from_functor.
Provides seqan3::detail::all.
@ single
The text is a single range.
Definition: concept.hpp:93
constexpr auto join_with
A view adaptor that represents view consisting of the sequence obtained from flattening a view of ran...
Definition: join_with.hpp:531
Provides implementation helper for seqan3::views::zip and seqan3::views::join_with.
The SeqAn namespace for views.
Definition: char_strictly_to.hpp:22
SeqAn specific customisations in the standard namespace.
Provides seqan3::detail::views::non_propagating_cache.