SeqAn3 3.1.0
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
23namespace seqan3::detail
24{
37template <typename char_t, typename traits_t = std::char_traits<char_t>>
38class fast_ostreambuf_iterator
39{
40private:
42 stream_buffer_exposer<char_t, traits_t> * stream_buf = nullptr;
43
44public:
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
The <algorithm> header from C++20's standard library.
T begin(T... args)
T end(T... args)
The <iterator> header from C++20's standard library.
SeqAn specific customisations in the standard namespace.
The <ranges> header from C++20's standard library.
The <charconv> header from C++17's standard library.
Provides seqan3::detail::stream_buffer_exposer.
T to_chars(T... args)