BioC++ core-0.7.0
The Modern C++ libraries for Bioinformatics.
 
Loading...
Searching...
No Matches
take.hpp
Go to the documentation of this file.
1// -----------------------------------------------------------------------------------------------------
2// Copyright (c) 2022 deCODE Genetics
3// Copyright (c) 2006-2020, Knut Reinert & Freie Universität Berlin
4// Copyright (c) 2016-2020, Knut Reinert & MPI für molekulare Genetik
5// This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License
6// shipped with this file and also available at: https://github.com/biocpp/biocpp-core/blob/main/LICENSE.md
7// -----------------------------------------------------------------------------------------------------
8
14#pragma once
15
16#include <algorithm>
17#include <concepts>
18#include <iterator>
19#include <ranges>
20#include <span>
21#include <type_traits>
22
30
31namespace bio::ranges::detail
32{
33
34// ============================================================================
35// view_take
36// ============================================================================
37
53template <std::ranges::view urng_t, bool exactly, bool or_throw>
54class view_take
56: public std::ranges::view_interface<view_take<urng_t, exactly, or_throw>>
58{
59private:
61 urng_t urange;
62
64 size_t target_size;
65
67 template <typename rng_t>
68 class basic_iterator;
69
70private:
75 using iterator = basic_iterator<urng_t>;
81 using const_iterator = basic_iterator<urng_t const>;
83
84public:
88 view_take() = default;
89 view_take(view_take const & rhs) = default;
90 view_take(view_take && rhs) noexcept = default;
91 view_take & operator=(view_take const & rhs) = default;
92 view_take & operator=(view_take && rhs) noexcept = default;
93 ~view_take() = default;
94
100 constexpr view_take(urng_t _urange, size_t const _size) : urange{std::move(_urange)}, target_size{_size}
101 {
102 if constexpr (std::ranges::sized_range<urng_t>)
103 {
104 if (std::ranges::size(urange) < target_size)
105 {
106 if constexpr (exactly && or_throw)
107 {
109 "You are trying to construct a views::take_exactly_or_throw from a range that is strictly "
110 "smaller."};
111 }
112 else
113 {
114 target_size = std::ranges::size(urange);
115 }
116 }
117 }
118 }
119
126 template <std::ranges::viewable_range rng_t>
127 requires std::constructible_from<rng_t, std::views::all_t<rng_t>>
128 constexpr view_take(rng_t && _urange, size_t const _size) :
129 view_take{std::views::all(std::forward<rng_t>(_urange)), _size}
130 {}
132
149 constexpr auto begin() noexcept
150 {
151 if constexpr (std::ranges::random_access_range<urng_t> && (std::ranges::sized_range<urng_t> || exactly))
152 return std::ranges::begin(urange);
153 else
154 return iterator{std::ranges::begin(urange), 0, target_size, this};
155 }
156
158 constexpr auto begin() const noexcept
159 requires const_iterable_range<urng_t>
160 {
161 if constexpr (std::ranges::random_access_range<urng_t> && (std::ranges::sized_range<urng_t> || exactly))
162 return std::ranges::begin(urange);
163 else
164 return const_iterator{std::ranges::begin(urange), 0, target_size};
165 }
166
180 constexpr auto end() noexcept
181 {
182 if constexpr (std::ranges::random_access_range<urng_t> && (std::ranges::sized_range<urng_t> || exactly))
183 return std::ranges::begin(urange) + target_size;
184 else
185 return std::ranges::end(urange);
186 }
187
189 constexpr auto end() const noexcept
190 requires const_iterable_range<urng_t>
191 {
192 if constexpr (std::ranges::random_access_range<urng_t> && (std::ranges::sized_range<urng_t> || exactly))
193 return std::ranges::begin(urange) + target_size;
194 else
195 return std::ranges::end(urange);
196 }
198
214 constexpr auto size() const noexcept
215 requires exactly || std::ranges::sized_range<urng_t>
216 {
217 return target_size;
218 }
219};
220
223template <typename urng_t, bool exactly = false, bool or_throw = false>
224view_take(urng_t &&, size_t) -> view_take<std::views::all_t<urng_t>, exactly, or_throw>;
225
228template <std::ranges::view urng_t, bool exactly, bool or_throw>
229template <typename rng_t>
230class view_take<urng_t, exactly, or_throw>::basic_iterator
232 : public inherited_iterator_base<basic_iterator<rng_t>, std::ranges::iterator_t<rng_t>>
234{
235private:
237 using base_base_t = std::ranges::iterator_t<rng_t>;
239 using base_t = inherited_iterator_base<basic_iterator, std::ranges::iterator_t<rng_t>>;
240
242 using sentinel_type = std::ranges::sentinel_t<urng_t>;
243
245 size_t pos{};
246
248 size_t max_pos{};
249
252
253public:
258 basic_iterator() = default;
259 basic_iterator(basic_iterator const & rhs) = default;
260 basic_iterator(basic_iterator && rhs) noexcept = default;
261 basic_iterator & operator=(basic_iterator const & rhs) = default;
262 basic_iterator & operator=(basic_iterator && rhs) noexcept = default;
263 ~basic_iterator() = default;
264
266 constexpr basic_iterator(base_base_t const & it) noexcept(noexcept(base_t{it})) : base_t{std::move(it)} {}
267
269 constexpr basic_iterator(base_base_t it,
270 size_t const _pos,
271 size_t const _max_pos,
272 view_take * host = nullptr) noexcept(noexcept(base_t{it})) :
273 base_t{std::move(it)}, pos{_pos}, max_pos(_max_pos)
274 {
275 host_ptr = host;
276 }
278
285 using difference_type = std::iter_difference_t<base_base_t>;
287 using value_type = std::iter_value_t<base_base_t>;
289 using reference = std::iter_reference_t<base_base_t>;
291 using pointer = detail::iter_pointer_t<base_base_t>;
293 using iterator_category = detail::iterator_category_tag_t<base_base_t>;
295 using iterator_concept = detail::iterator_concept_tag_t<base_base_t>;
297
304 constexpr basic_iterator & operator++() noexcept(noexcept(++std::declval<base_t &>()))
305 {
306 base_t::operator++();
307 ++pos;
308 if constexpr (exactly && !std::forward_iterator<base_base_t>)
309 --host_ptr->target_size;
310 return *this;
311 }
312
314 constexpr basic_iterator operator++(int) noexcept(noexcept(++std::declval<basic_iterator &>()) &&
315 std::is_nothrow_copy_constructible_v<basic_iterator>)
316 {
317 basic_iterator cpy{*this};
318 ++(*this);
319 return cpy;
320 }
321
323 constexpr basic_iterator & operator--() noexcept(noexcept(--std::declval<base_base_t &>()))
324 requires std::bidirectional_iterator<base_base_t>
325 {
326 base_t::operator--();
327 --pos;
328 return *this;
329 }
330
332 constexpr basic_iterator operator--(int) noexcept(noexcept(--std::declval<basic_iterator &>()) &&
333 std::is_nothrow_copy_constructible_v<basic_iterator>)
334 requires std::bidirectional_iterator<base_base_t>
335 {
336 basic_iterator cpy{*this};
337 --(*this);
338 return cpy;
339 }
340
342 constexpr basic_iterator & operator+=(difference_type const skip) noexcept(noexcept(std::declval<base_t &>() +=
343 skip))
344 requires std::random_access_iterator<base_base_t>
345 {
346 base_t::operator+=(skip);
347 pos += skip;
348 return *this;
349 }
350
352 constexpr basic_iterator & operator-=(difference_type const skip) noexcept(noexcept(std::declval<base_t &>() -=
353 skip))
354 requires std::random_access_iterator<base_base_t>
355 {
356 base_t::operator-=(skip);
357 pos -= skip;
358 return *this;
359 }
361
368 constexpr bool operator==(basic_iterator const & rhs) const
369 noexcept(!or_throw && noexcept(std::declval<base_base_t &>() == std::declval<base_base_t &>()))
370 requires std::forward_iterator<base_base_t>
371 {
372 return *base_t::this_to_base() == *rhs.this_to_base();
373 }
374
376 constexpr friend bool operator==(basic_iterator const & lhs, sentinel_type const & rhs) noexcept(
377 !or_throw && noexcept(std::declval<base_base_t const &>() == std::declval<sentinel_type const &>()))
378 {
379 if (lhs.pos >= lhs.max_pos)
380 return true;
381
382 if (static_cast<base_base_t>(lhs) == rhs)
383 {
384 if constexpr (or_throw)
385 throw std::runtime_error{"Reached end of input before designated size."};
386
387 return true;
388 }
389 else
390 {
391 return false;
392 }
393 }
395
405 constexpr reference operator[](std::make_unsigned_t<difference_type> const n) const
406 noexcept(noexcept(std::declval<base_base_t &>()[0]))
407 requires std::random_access_iterator<base_base_t>
408 {
409 return base_base_t::operator[](n);
410 }
412};
413
414// ============================================================================
415// take_fn (adaptor definition)
416// ============================================================================
417
421template <bool exactly, bool or_throw>
422struct take_fn
423{
425 constexpr auto operator()(size_t const size) const { return adaptor_from_functor{*this, size}; }
426
430 template <std::ranges::range urng_t>
431 constexpr auto operator()(urng_t && urange, size_t target_size) const
432 {
433 static_assert(std::ranges::viewable_range<urng_t>,
434 "The views::take adaptor can only be passed viewable_ranges, i.e. Views or &-to-non-View.");
435
436 // safeguard against wrong size
437 if constexpr (std::ranges::sized_range<urng_t>)
438 {
439 if constexpr (or_throw)
440 {
441 if (target_size > std::ranges::size(urange))
442 {
444 "You are trying to construct a views::take_exactly_or_throw from a "
445 "range that is strictly smaller."};
446 }
447 }
448 else
449 {
450 target_size = std::min<size_t>(target_size, std::ranges::size(urange));
451 }
452 }
453
454 // string_view
455 if constexpr (meta::is_type_specialisation_of_v<std::remove_cvref_t<urng_t>, std::basic_string_view>)
456 {
457 return urange.substr(0, target_size);
458 }
459 // string const &
460 else if constexpr (meta::is_type_specialisation_of_v<std::remove_cvref_t<urng_t>, std::basic_string> &&
461 std::is_const_v<std::remove_reference_t<urng_t>>)
462 {
463 return std::basic_string_view{std::ranges::data(urange), target_size};
464 }
465 // contiguous
466 else if constexpr (std::ranges::borrowed_range<urng_t> && std::ranges::contiguous_range<urng_t> &&
467 std::ranges::sized_range<urng_t>)
468 {
469 return std::span{std::ranges::data(urange), target_size};
470 }
471 // random_access
472 else if constexpr (std::ranges::borrowed_range<urng_t> && std::ranges::random_access_range<urng_t> &&
473 std::ranges::sized_range<urng_t>)
474 {
475 return std::ranges::subrange<std::ranges::iterator_t<urng_t>, std::ranges::iterator_t<urng_t>>{
476 std::ranges::begin(urange),
477 std::ranges::begin(urange) + target_size,
478 target_size};
479 }
480 // our type
481 else
482 {
483 return view_take<std::views::all_t<urng_t>, exactly, or_throw>{std::forward<urng_t>(urange), target_size};
484 }
485 }
486};
487
488} // namespace bio::ranges::detail
T begin(T... args)
T end(T... args)
T forward(T... args)
constexpr auto size
A type trait that holds the size of a (semi-)alphabet.
Definition: concept.hpp:517
std::remove_cvref_t< decltype(std::ignore)> ignore_t
Return the type of std::ignore with const, volatile and references removed (type trait).
Definition: basic.hpp:48
Provides the bio::ranges::detail::inherited_iterator_base template.
T move(T... args)
Additional non-standard concepts for ranges.
Adaptations of concepts from the standard library.
Auxiliary header for the views submodule .
Provides various traits to inspect templates.
Provides bio::meta::transformation_trait_or.
Provides various transformation traits used by the range module.