BioC++ core-0.7.0
The Modern C++ libraries for Bioinformatics.
 
Loading...
Searching...
No Matches
char_to.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 <concepts>
17#include <ranges>
18#include <type_traits>
19
27
28#include "bio/alphabet/detail/to_lower.hpp"
31
32namespace bio::ranges::detail
33{
34
35// ---------------------------------------------------------------------------------------------------------------------
36// char_to_cigar_view class
37// ---------------------------------------------------------------------------------------------------------------------
38
45template <std::ranges::view urng_t>
46 requires std::ranges::forward_range<urng_t>
47class char_to_cigar_view : public std::ranges::view_interface<char_to_cigar_view<urng_t>>
48{
49private:
51 urng_t urange;
52
54 template <typename uit_t, typename usen_t>
55 class iterator;
56
58 using it_t = iterator<std::ranges::iterator_t<urng_t>, std::ranges::sentinel_t<urng_t>>;
60 using const_it_t =
62 iterator<std::ranges::iterator_t<urng_t const>, std::ranges::sentinel_t<urng_t const>>,
63 void>;
64
65public:
69 char_to_cigar_view() = default;
70 char_to_cigar_view(char_to_cigar_view const &) = default;
71 char_to_cigar_view & operator=(char_to_cigar_view const &) = default;
72 char_to_cigar_view(char_to_cigar_view &&) noexcept = default;
73 char_to_cigar_view & operator=(char_to_cigar_view &&) noexcept = default;
74 ~char_to_cigar_view() = default;
75
77 constexpr explicit char_to_cigar_view(urng_t _urange) : urange{std::move(_urange)} {}
79
98 constexpr auto begin() noexcept
99 {
100 return ++it_t{std::ranges::begin(urange), std::ranges::begin(urange), std::ranges::end(urange)};
101 }
102
104 constexpr auto begin() const noexcept
105 requires const_iterable_range<urng_t>
106 {
107 return ++const_it_t{std::ranges::begin(urange), std::ranges::begin(urange), std::ranges::end(urange)};
108 }
109
125 constexpr auto end() noexcept
126 {
127 if constexpr (std::ranges::common_range<urng_t>)
128 return it_t{std::ranges::end(urange), std::ranges::begin(urange), std::ranges::end(urange)};
129 else
130 return std::ranges::end(urange);
131 }
132
134 constexpr auto end() const noexcept
135 requires const_iterable_range<urng_t>
136 {
137 if constexpr (std::ranges::common_range<urng_t>)
138 return const_it_t{std::ranges::end(urange), std::ranges::begin(urange), std::ranges::end(urange)};
139 else
140 return std::ranges::end(urange);
141 }
143};
144
145// ---------------------------------------------------------------------------------------------------------------------
146// char_to_cigar_view::iterator class
147// ---------------------------------------------------------------------------------------------------------------------
148
149template <std::ranges::view urng_t>
150 requires std::ranges::forward_range<urng_t>
151template <typename uit_t, typename usen_t>
152class char_to_cigar_view<urng_t>::iterator
153{
154private:
156 static constexpr alphabet::cigar default_value{(2u << 28) - 1, alphabet::assign_char_to('B', alphabet::cigar_op{})};
157
159 static constexpr bool is_digit(char const c) { return c >= '0' && c <= '9'; }
160
162 static constexpr bool is_alpha(char const c)
163 {
164 return alphabet::detail::is_lower(c) || alphabet::detail::is_upper(c);
165 }
166
168 uit_t uit_left;
170 uit_t uit_right;
172 uit_t ubeg;
174 usen_t usen;
176 alphabet::cigar value = default_value;
177
179 static constexpr bool nothrow_default_init =
180 std::is_nothrow_default_constructible_v<uit_t> && std::is_nothrow_default_constructible_v<usen_t>;
182 static constexpr bool nothrow_move_init =
183 std::is_nothrow_move_constructible_v<uit_t> && std::is_nothrow_move_constructible_v<usen_t>;
185 static constexpr bool nothrow_copy_init =
186 std::is_nothrow_copy_constructible_v<uit_t> && std::is_nothrow_copy_constructible_v<usen_t>;
188 static constexpr bool nothrow_move_assign =
189 std::is_nothrow_move_assignable_v<uit_t> && std::is_nothrow_move_assignable_v<usen_t>;
191 static constexpr bool nothrow_copy_assign =
192 std::is_nothrow_copy_assignable_v<uit_t> && std::is_nothrow_copy_assignable_v<usen_t>;
193
194public:
201 using difference_type = std::iter_difference_t<uit_t>;
203 using value_type = alphabet::cigar;
205 using reference = alphabet::cigar;
207 using pointer = void *;
209 using iterator_category = std::input_iterator_tag;
213 detail::iterator_concept_tag_t<uit_t>>;
215
220 constexpr iterator() noexcept(nothrow_default_init) = default;
221 constexpr iterator(iterator const & rhs) noexcept(nothrow_copy_init) = default;
222 constexpr iterator(iterator && rhs) noexcept(nothrow_move_init) = default;
223 constexpr iterator & operator=(iterator const & rhs) noexcept(nothrow_copy_assign) = default;
224 constexpr iterator & operator=(iterator && rhs) noexcept(nothrow_move_assign) = default;
225 ~iterator() noexcept(std::is_nothrow_destructible_v<uit_t>) = default;
226
228 constexpr iterator(uit_t const it, uit_t const beg, usen_t const sen) noexcept(nothrow_copy_init) :
229 uit_left{it}, uit_right{it}, ubeg{beg}, usen{sen}
230 {}
232
238 constexpr friend bool operator==(iterator const & lhs, iterator const & rhs) noexcept(
239 noexcept(std::declval<uit_t &>() == std::declval<uit_t &>()))
240 {
241 return lhs.uit_left == rhs.uit_left;
242 }
243
245 constexpr friend bool operator==(iterator const & lhs, usen_t const & rhs) noexcept(
246 noexcept(std::declval<uit_t &>() == std::declval<usen_t &>()))
247 requires(!std::same_as<uit_t, usen_t>)
248 {
249 return lhs.uit_left == rhs;
250 }
251
253 constexpr friend auto operator<=>(iterator const & lhs, iterator const & rhs) noexcept(
254 noexcept(std::declval<uit_t &>() < std::declval<uit_t &>()))
255 requires std::totally_ordered<uit_t>
256 {
257 return lhs.uit_left <=> rhs.uit_left;
258 }
260
266 constexpr iterator & operator++()
267 {
268 value = default_value;
269
270 if (uit_left != uit_right) // every increment except the first
271 uit_left = uit_right;
272
273 if (uit_left == usen) // at end
274 return *this;
275
276 while (!is_alpha(*uit_right))
277 {
278 assert(is_digit(*uit_right));
279 ++uit_right;
280 assert(uit_right != usen);
281 }
282
283 ++uit_right; // go behind alpha
284
285 return *this;
286 }
287
289 constexpr auto operator++(int)
290 {
291 auto copy = *this;
292 ++(*this);
293 return copy;
294 }
295
297 constexpr iterator & operator--()
298 requires(requires(uit_t i) { --i; })
299 {
300 assert(uit_left != ubeg);
301
302 value = default_value;
303
304 uit_right = uit_left;
305
306 --uit_left;
307 assert(is_alpha(*uit_left));
308
309 do
310 {
311 --uit_left;
312 }
313 while (is_digit(*uit_left) && uit_left != ubeg);
314
315 if (uit_left != ubeg)
316 ++uit_left;
317
318 return *this;
319 }
320
322 constexpr auto operator--(int)
323 requires(requires(uit_t i) { --i; })
324 {
325 auto copy = *this;
326 --(*this);
327 return copy;
328 }
330
335 constexpr value_type operator*()
336 {
337 if (value == default_value)
338 {
339 if constexpr (std::contiguous_iterator<uit_t>)
340 {
341 std::string_view v{uit_left, uit_right};
342 value.assign_string(v);
343 }
344 else
345 {
346 std::string s;
347 std::ranges::copy(uit_left, uit_right, std::back_inserter(s));
348 value.assign_string(s);
349 }
350 }
351 return value;
352 }
353
355 constexpr value_type operator*() const
356 {
357 alphabet::cigar c;
358
359 if constexpr (std::contiguous_iterator<uit_t>)
360 {
361 std::string_view v{uit_left, uit_right};
362 c.assign_string(v);
363 }
364 else
365 {
366 std::string s;
367 std::ranges::copy(uit_left, uit_right, std::back_inserter(s));
368 c.assign_string(s);
369 }
370 return c;
371 }
372
374 constexpr pointer operator->() noexcept(noexcept(*std::declval<uit_t &>()))
375 requires std::input_iterator<uit_t>
376 {
377 return this;
378 }
379
381 constexpr decltype(auto) operator->() const noexcept(noexcept(*std::declval<uit_t const &>()))
382 requires std::input_iterator<uit_t>
383 {
384 return this;
385 }
387};
388
389} // namespace bio::ranges::detail
390
391// ---------------------------------------------------------------------------------------------------------------------
392// enable_borrowed_range
393// ---------------------------------------------------------------------------------------------------------------------
394
396// Mark char_to_cigar_view as conditionally borrowed.
397template <typename urng_t>
398inline constexpr bool std::ranges::enable_borrowed_range<bio::ranges::detail::char_to_cigar_view<urng_t>> =
399 std::ranges::borrowed_range<urng_t>;
401
402// ---------------------------------------------------------------------------------------------------------------------
403// views::char_to
404// ---------------------------------------------------------------------------------------------------------------------
405
406namespace bio::ranges::views
407{
408
489template <typename alphabet_type>
490 requires(alphabet::alphabet<alphabet_type> || std::same_as<alphabet_type, alphabet::cigar>)
491inline constexpr auto char_to = detail::adaptor_from_functor{meta::overloaded{
492 // clang-format off
493 // cigar special case below
494 // char2char special case
495 []<std::ranges::input_range rng_t>(rng_t && range)
497 std::same_as<ranges::range_innermost_value_t<rng_t>, alphabet_type>)
498 {
499 return std::forward<rng_t>(range) | views::type_reduce; // NOP
500 },
501 // generic case
502 []<std::ranges::input_range rng_t>(rng_t && range)
504 {
505 auto fn = [] (alphabet::char_t<alphabet_type> const in) -> alphabet_type
506 {
507 return alphabet::assign_char_to(in, alphabet_type{});
508 };
509 return std::forward<rng_t>(range) | deep{std::views::transform(fn)};
510 },
511 // catch-all
512 []<typename rng_t>(rng_t &&)
513 {
514 static_assert(meta::always_false<rng_t>,
515 "The type you pass to bio::views::char_to must be a range of elements convertible "
516 "to the target alphabet's character type.");
517 }}};
518// clang-format on
519
520template <>
521inline constexpr auto char_to<alphabet::cigar> = detail::adaptor_from_functor{
522 // clang-format off
523 []<typename rng_t>(rng_t && range)
524 {
525 static_assert(std::ranges::forward_range<rng_t> && std::same_as<std::ranges::range_value_t<rng_t>, char>,
526 "The type you pass to bio::views::char_to<bio::alphabet::cigar> must be a forward_range "
527 "over char.");
528 return detail::char_to_cigar_view{views::type_reduce(std::forward<rng_t>(range))};
529 }};
530// clang-format on
531
533
534} // namespace bio::ranges::views
Meta-header for the custom submodule; includes all headers from alphabet/custom/.
T back_inserter(T... args)
T begin(T... args)
Provides the bio::alphabet::cigar alphabet.
A wrapper type around an existing view adaptor that enables "deep view" behaviour for that view.
Definition: deep.hpp:104
T copy(T... args)
Provides bio::views::deep.
T end(T... args)
Exceptions thrown by entities in the alphabet module.
constexpr auto assign_char_to
Assign a char to an alphabet object.
Definition: concept.hpp:260
decltype(bio::alphabet::to_char(std::declval< alphabet_type const >())) char_t
The char_type of the alphabet; defined as the return type of bio::alphabet::to_char.
Definition: concept.hpp:212
typename range_innermost_value< t >::type range_innermost_value_t
Shortcut for bio::ranges::range_innermost_value (transformation_trait shortcut).
Definition: type_traits.hpp:185
constexpr auto type_reduce
A view adaptor that behaves like std::views::all, but type erases certain ranges.
Definition: type_reduce.hpp:152
constexpr auto char_to
A view over an alphabet, given a range of characters.
Definition: char_to.hpp:491
The BioC++ namespace for views.
Provides bio::meta::overloaded.
Additional non-standard concepts for ranges.
A constexpr string implementation to manipulate string literals at compile time.
Wrapper to create an overload set of multiple functors.
Definition: overloaded.hpp:37
Provides bio::views::type_reduce.
Provides various transformation traits used by the range module.