SeqAn3  3.0.3
The Modern C++ library for sequence analysis.
fast_ostreambuf_iterator.hpp
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------------------------------
2 // Copyright (c) 2006-2021, Knut Reinert & Freie Universität Berlin
3 // Copyright (c) 2016-2021, 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 
14 #pragma once
15 
16 #include <seqan3/std/algorithm>
17 #include <seqan3/std/charconv>
18 #include <seqan3/std/iterator>
19 #include <seqan3/std/ranges>
20 
22 
23 namespace seqan3::detail
24 {
37 template <typename char_t, typename traits_t = std::char_traits<char_t>>
38 class fast_ostreambuf_iterator
39 {
40 private:
42  stream_buffer_exposer<char_t, traits_t> * stream_buf = nullptr;
43 
44 public:
48  using difference_type = ptrdiff_t;
49  using value_type = char_t;
50  using reference = char_t;
51  using pointer = void;
52  using iterator_category = std::output_iterator_tag;
54 
58  fast_ostreambuf_iterator() noexcept = default;
59  fast_ostreambuf_iterator(fast_ostreambuf_iterator const &) noexcept = default;
60  fast_ostreambuf_iterator(fast_ostreambuf_iterator &&) noexcept = default;
61  fast_ostreambuf_iterator & operator=(fast_ostreambuf_iterator const &) noexcept = default;
62  fast_ostreambuf_iterator & operator=(fast_ostreambuf_iterator &&) noexcept = default;
63  ~fast_ostreambuf_iterator() noexcept = default;
64 
66  explicit fast_ostreambuf_iterator(std::basic_streambuf<char_t, traits_t> & ibuf) :
67  stream_buf{reinterpret_cast<stream_buffer_exposer<char_t, traits_t> *>(&ibuf)}
68  {
69  assert(stream_buf != nullptr);
70  if (stream_buf->pptr() == stream_buf->epptr())
71  stream_buf->overflow(); // ensures that put area has space available
72  }
74 
79  fast_ostreambuf_iterator & operator++()
80  {
81  return *this;
82  }
84  fast_ostreambuf_iterator & operator++(int)
85  {
86  return *this;
87  }
89 
91  fast_ostreambuf_iterator & operator*()
92  {
93  return *this;
94  }
95 
97  fast_ostreambuf_iterator & operator=(char_t const c)
98  {
99  assert(stream_buf != nullptr);
100  if (stream_buf->pptr() == stream_buf->epptr())
101  {
102  if (stream_buf->sputc(c) == traits_t::eof()) // overflow() [virtual], then write character
103  {
104  // LCOV_EXCL_START
105  throw std::ios_base::failure{"Cannot write to output stream (reached traits::eof() condition)."};
106  // LCOV_EXCL_STOP
107  }
108  }
109  else
110  {
111  *stream_buf->pptr() = c;
112  stream_buf->pbump(1); // advance pptr() in put area without any checks
113  }
114  return *this;
115  }
116 
118  bool failed() const noexcept
119  {
120  return stream_buf->overflow() == traits_t::eof();
121  }
122 
141  template <std::ranges::forward_range range_type>
143  requires std::ranges::borrowed_range<range_type>
145  auto write_range(range_type && rng)
146  {
147  using sen_t = std::ranges::sentinel_t<range_type>;
148  using it_t = std::ranges::iterator_t<range_type>;
149 
150  it_t it = std::ranges::begin(rng);
151  sen_t end = std::ranges::end(rng);
152 
153  while (it != end)
154  {
155  size_t const buffer_space = stream_buf->epptr() - stream_buf->pptr();
156 
157  if constexpr (std::ranges::sized_range<range_type>)
158  {
159  size_t const characters_to_write = std::min<size_t>(std::ranges::distance(it, end), buffer_space);
160  auto copy_res = std::ranges::copy_n(it, characters_to_write, stream_buf->pptr());
161  it = copy_res.in;
162  stream_buf->pbump(characters_to_write);
163  }
164  else
165  {
166  size_t i = 0;
167  for (; it != end && i < buffer_space; ++it, ++i)
168  *stream_buf->pptr() = *it;
169  stream_buf->pbump(i);
170  }
171 
172  if (it == end) // no more characters to write
173  return it;
174 
175  // Push one more character and flush
176  if (stream_buf->overflow(*it) == traits_t::eof())
177  {
178  // LCOV_EXCL_START
179  throw std::ios_base::failure{"Cannot write to output stream (reached traits::eof() condition)."};
180  // LCOV_EXCL_STOP
181  }
182 
183  ++it; // drop 1 character that has been written in overflow()
184  }
185 
186  return it;
187  }
188 
190  // overload for non-std::ranges::borrowed_range types that return void
191  template <std::ranges::forward_range range_type>
192  void write_range(range_type && rng)
193  {
194  write_range(rng); // lvalue is always a safe range. return value is ignored because iterator would be dangling
195  }
197 
202  template <typename number_type>
204  requires std::is_arithmetic_v<number_type>
206  auto write_number(number_type num)
207  {
208  if (stream_buf->epptr() - stream_buf->pptr() > 300) // enough space for any number, should be likely
209  {
210  auto res = std::to_chars(stream_buf->pptr(), stream_buf->epptr(), num);
211  stream_buf->pbump(res.ptr - stream_buf->pptr()); // advance pptr
212  }
213  else
214  {
215  std::array<char, 300> arithmetic_buffer{};
216  auto res = std::to_chars(&arithmetic_buffer[0], &arithmetic_buffer[0] + sizeof(arithmetic_buffer), num);
217  write_range(std::ranges::subrange<char *, char *>(&arithmetic_buffer[0], res.ptr));
218  }
219  }
220 
225  void write_end_of_line(bool const add_cr)
226  {
227  if (add_cr)
228  *this = '\r';
229  *this = '\n';
230  }
231 };
232 
233 } // namespace seqan3::detail
Adaptations of algorithms from the Ranges TS.
T begin(T... args)
T end(T... args)
Provides C++20 additions to the <iterator> header.
SeqAn specific customisations in the standard namespace.
Adaptations of concepts from the Ranges TS.
Provides std::from_chars and std::to_chars if not defined in the stdlib <charconv> header.
Provides seqan3::detail::stream_buffer_exposer.
T to_chars(T... args)