SeqAn3  3.0.2
The Modern C++ library for sequence analysis.
iterator.hpp
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------------------------------
2 // Copyright (c) 2006-2020, Knut Reinert & Freie Universität Berlin
3 // Copyright (c) 2016-2020, Knut Reinert & MPI für molekulare Genetik
4 // This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License
5 // shipped with this file and also available at: https://github.com/seqan/seqan3/blob/master/LICENSE.md
6 // -----------------------------------------------------------------------------------------------------
7 
15 #pragma once
16 
17 #include <seqan3/std/algorithm>
18 #include <seqan3/std/charconv>
19 #include <seqan3/std/iterator>
20 #include <seqan3/std/ranges>
21 
22 #include <seqan3/core/platform.hpp>
26 
27 namespace seqan3::detail
28 {
29 // ============================================================================
30 // fast_istreambuf_iterator
31 // ============================================================================
32 
43 template <typename char_t, typename traits_t = std::char_traits<char_t>>
44 struct stream_buffer_exposer : public std::basic_streambuf<char_t, traits_t>
45 {
48 
50  // Expose protected members:
51  using base_t::eback;
52  using base_t::gptr;
53  using base_t::egptr;
54  using base_t::gbump;
55  using base_t::underflow;
56 
57  using base_t::pbase;
58  using base_t::pptr;
59  using base_t::epptr;
60  using base_t::pbump;
61  using base_t::overflow;
63 };
64 
77 template <typename char_t, typename traits_t = std::char_traits<char_t>>
78 class fast_istreambuf_iterator
79 {
80 private:
82  stream_buffer_exposer<char_t, traits_t> * stream_buf = nullptr;
83 
84 public:
88  using difference_type = ptrdiff_t;
89  using value_type = char_t;
90  using reference = char_t;
91  using pointer = void;
92  using iterator_category = std::input_iterator_tag;
93 
98  fast_istreambuf_iterator() noexcept = default;
99  fast_istreambuf_iterator(fast_istreambuf_iterator const &) noexcept = default;
100  fast_istreambuf_iterator(fast_istreambuf_iterator &&) noexcept = default;
101  fast_istreambuf_iterator & operator=(fast_istreambuf_iterator const &) noexcept = default;
102  fast_istreambuf_iterator & operator=(fast_istreambuf_iterator &&) noexcept = default;
103  ~fast_istreambuf_iterator() noexcept = default;
104 
106  explicit fast_istreambuf_iterator(std::basic_streambuf<char_t, traits_t> & ibuf) :
107  stream_buf{reinterpret_cast<stream_buffer_exposer<char_t, traits_t> *>(&ibuf)}
108  {
109  assert(stream_buf != nullptr);
110  stream_buf->underflow(); // ensure the stream buffer has content on construction
111  }
113 
117  fast_istreambuf_iterator & operator++()
119  {
120  assert(stream_buf != nullptr);
121  if ((stream_buf->gptr() + 1) == stream_buf->egptr())
122  stream_buf->snextc(); // move right, then underflow()
123  else
124  stream_buf->gbump(1);
125  return *this;
126  }
127 
129  void operator++(int)
130  {
131  ++(*this);
132  }
134 
136  reference operator*() const
137  {
138  assert(stream_buf != nullptr);
139  return *stream_buf->gptr();
140  }
141 
146  friend bool operator==(fast_istreambuf_iterator const & lhs, std::default_sentinel_t const &) noexcept
148  {
149  assert(lhs.stream_buf != nullptr);
150  // compare size of remaining buffer; since ++ always resizes if possible, safe to compare pointers here
151  return (lhs.stream_buf->gptr() == lhs.stream_buf->egptr());
152  }
153 
155  friend bool operator!=(fast_istreambuf_iterator const & lhs, std::default_sentinel_t const &) noexcept
156  {
157  return !(lhs == std::default_sentinel);
158  }
159 
161  friend bool operator==(std::default_sentinel_t const &, fast_istreambuf_iterator const & rhs) noexcept
162  {
163  return rhs == std::default_sentinel;
164  }
165 
167  friend bool operator!=(std::default_sentinel_t const &, fast_istreambuf_iterator const & rhs) noexcept
168  {
169  return !(rhs == std::default_sentinel);
170  }
172 };
173 
186 template <typename char_t, typename traits_t = std::char_traits<char_t>>
187 class fast_ostreambuf_iterator
188 {
189 private:
191  stream_buffer_exposer<char_t, traits_t> * stream_buf = nullptr;
192 
193 public:
197  using difference_type = ptrdiff_t;
198  using value_type = char_t;
199  using reference = char_t;
200  using pointer = void;
201  using iterator_category = std::output_iterator_tag;
202 
207  fast_ostreambuf_iterator() noexcept = default;
208  fast_ostreambuf_iterator(fast_ostreambuf_iterator const &) noexcept = default;
209  fast_ostreambuf_iterator(fast_ostreambuf_iterator &&) noexcept = default;
210  fast_ostreambuf_iterator & operator=(fast_ostreambuf_iterator const &) noexcept = default;
211  fast_ostreambuf_iterator & operator=(fast_ostreambuf_iterator &&) noexcept = default;
212  ~fast_ostreambuf_iterator() noexcept = default;
213 
215  explicit fast_ostreambuf_iterator(std::basic_streambuf<char_t, traits_t> & ibuf) :
216  stream_buf{reinterpret_cast<stream_buffer_exposer<char_t, traits_t> *>(&ibuf)}
217  {
218  assert(stream_buf != nullptr);
219  if (stream_buf->pptr() == stream_buf->epptr())
220  stream_buf->overflow(); // ensures that put area has space available
221  }
223 
227  fast_ostreambuf_iterator & operator++()
229  {
230  return *this;
231  }
233  fast_ostreambuf_iterator & operator++(int)
234  {
235  return *this;
236  }
238 
240  fast_ostreambuf_iterator & operator*()
241  {
242  return *this;
243  }
244 
246  fast_ostreambuf_iterator & operator=(char_t const c)
247  {
248  assert(stream_buf != nullptr);
249  if (stream_buf->pptr() == stream_buf->epptr())
250  {
251  if (stream_buf->sputc(c) == traits_t::eof()) // overflow() [virtual], then write character
252  {
253  // LCOV_EXCL_START
254  throw std::ios_base::failure{"Cannot write to output stream (reached traits::eof() condition)."};
255  // LCOV_EXCL_STOP
256  }
257  }
258  else
259  {
260  *stream_buf->pptr() = c;
261  stream_buf->pbump(1); // advance pptr() in put area without any checks
262  }
263  return *this;
264  }
265 
267  bool failed() const noexcept
268  {
269  return stream_buf->overflow() == traits_t::eof();
270  }
271 
290  template <std::ranges::forward_range range_type>
292  requires std::ranges::borrowed_range<range_type>
294  auto write_range(range_type && rng)
295  {
296  using sen_t = std::ranges::sentinel_t<range_type>;
297  using it_t = std::ranges::iterator_t<range_type>;
298 
299  it_t it = std::ranges::begin(rng);
300  sen_t end = std::ranges::end(rng);
301 
302  while (it != end)
303  {
304  size_t const buffer_space = stream_buf->epptr() - stream_buf->pptr();
305 
306  if constexpr (std::ranges::sized_range<range_type>)
307  {
308  size_t const characters_to_write = std::min<size_t>(std::ranges::distance(it, end), buffer_space);
309  auto copy_res = std::ranges::copy_n(it, characters_to_write, stream_buf->pptr());
310  it = copy_res.in;
311  stream_buf->pbump(characters_to_write);
312  }
313  else
314  {
315  size_t i = 0;
316  for (; it != end && i < buffer_space; ++it, ++i)
317  *stream_buf->pptr() = *it;
318  stream_buf->pbump(i);
319  }
320 
321  if (it == end) // no more characters to write
322  return it;
323 
324  // Push one more character and flush
325  if (stream_buf->overflow(*it) == traits_t::eof())
326  {
327  // LCOV_EXCL_START
328  throw std::ios_base::failure{"Cannot write to output stream (reached traits::eof() condition)."};
329  // LCOV_EXCL_STOP
330  }
331 
332  ++it; // drop 1 character that has been written in overflow()
333  }
334 
335  return it;
336  }
337 
339  // overload for non-std::ranges::borrowed_range types that return void
340  template <std::ranges::forward_range range_type>
341  void write_range(range_type && rng)
342  {
343  write_range(rng); // lvalue is always a safe range. return value is ignored because iterator would be dangling
344  }
346 
351  template <arithmetic number_type>
352  auto write_number(number_type num)
353  {
354  if (stream_buf->epptr() - stream_buf->pptr() > 300) // enough space for any number, should be likely
355  {
356  auto res = std::to_chars(stream_buf->pptr(), stream_buf->epptr(), num);
357  stream_buf->pbump(res.ptr - stream_buf->pptr()); // advance pptr
358  }
359  else
360  {
361  std::array<char, 300> arithmetic_buffer{};
362  auto res = std::to_chars(&arithmetic_buffer[0], &arithmetic_buffer[0] + sizeof(arithmetic_buffer), num);
363  write_range(std::ranges::subrange<char *, char *>(&arithmetic_buffer[0], res.ptr));
364  }
365  }
366 
371  void write_end_of_line(bool const add_cr)
372  {
373  if (add_cr)
374  *this = '\r';
375  *this = '\n';
376  }
377 };
378 
379 } // namespace seqan3::detail
drop.hpp
Provides seqan3::views::drop.
charconv
Provides std::from_chars and std::to_chars if not defined in the stl <charconv> header.
std::rel_ops::operator!=
T operator!=(T... args)
std::basic_streambuf::pbase
T pbase(T... args)
iterator
Provides C++20 additions to the <iterator> header.
std::input_iterator_tag
std::ios_base::failure
std::basic_streambuf
std::basic_streambuf::pbump
T pbump(T... args)
algorithm
Adaptations of algorithms from the Ranges TS.
std::basic_streambuf::eback
T eback(T... args)
std::basic_streambuf::underflow
T underflow(T... args)
std::basic_streambuf::gbump
T gbump(T... args)
core_language.hpp
Provides concepts for core language types and relations that don't have concepts in C++20 (yet).
std::array
std::to_chars
T to_chars(T... args)
std::basic_streambuf::overflow
T overflow(T... args)
take.hpp
Provides seqan3::views::take.
ranges
Adaptations of concepts from the Ranges TS.
platform.hpp
Provides platform and dependency checks.
std::ranges::begin
T begin(T... args)
std
SeqAn specific customisations in the standard namespace.
std::end
T end(T... args)