SeqAn3 3.4.0-rc.4
The Modern C++ library for sequence analysis.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
fast_ostreambuf_iterator.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2006-2025 Knut Reinert & Freie Universität Berlin
2// SPDX-FileCopyrightText: 2016-2025 Knut Reinert & MPI für molekulare Genetik
3// SPDX-License-Identifier: BSD-3-Clause
4
11#pragma once
12
13#include <algorithm>
14#include <array>
15#include <cassert>
16#include <iterator>
17#include <ranges>
18#include <seqan3/std/charconv>
19
21
22namespace seqan3::detail
23{
36template <typename char_t, typename traits_t = std::char_traits<char_t>>
37class fast_ostreambuf_iterator
38{
39private:
41 stream_buffer_exposer<char_t, traits_t> * stream_buf = nullptr;
42
43public:
47 using difference_type = ptrdiff_t;
48 using value_type = char_t;
49 using reference = char_t;
50 using pointer = void;
51 using iterator_category = std::output_iterator_tag;
53
57 fast_ostreambuf_iterator() noexcept = default;
58 fast_ostreambuf_iterator(fast_ostreambuf_iterator const &) noexcept = default;
59 fast_ostreambuf_iterator(fast_ostreambuf_iterator &&) noexcept = default;
60 fast_ostreambuf_iterator & operator=(fast_ostreambuf_iterator const &) noexcept = default;
61 fast_ostreambuf_iterator & operator=(fast_ostreambuf_iterator &&) noexcept = default;
62 ~fast_ostreambuf_iterator() noexcept = default;
63
65 explicit fast_ostreambuf_iterator(std::basic_streambuf<char_t, traits_t> & ibuf) :
66 stream_buf{reinterpret_cast<stream_buffer_exposer<char_t, traits_t> *>(&ibuf)}
67 {
68 assert(stream_buf != nullptr);
69 if (stream_buf->pptr() == stream_buf->epptr())
70 stream_buf->overflow(); // ensures that put area has space available
71 }
73
78 fast_ostreambuf_iterator & operator++()
79 {
80 return *this;
81 }
83 fast_ostreambuf_iterator & operator++(int)
84 {
85 return *this;
86 }
88
90 fast_ostreambuf_iterator & operator*()
91 {
92 return *this;
93 }
94
96 fast_ostreambuf_iterator & operator=(char_t const c)
97 {
98 assert(stream_buf != nullptr);
99 if (stream_buf->pptr() == stream_buf->epptr())
100 {
101 if (stream_buf->sputc(c) == traits_t::eof()) // overflow() [virtual], then write character
102 {
103 // LCOV_EXCL_START
104 throw std::ios_base::failure{"Cannot write to output stream (reached traits::eof() condition)."};
105 // LCOV_EXCL_STOP
106 }
107 }
108 else
109 {
110 *stream_buf->pptr() = c;
111 stream_buf->pbump(1); // advance pptr() in put area without any checks
112 }
113 return *this;
114 }
115
117 bool failed() const noexcept
118 {
119 return stream_buf->overflow() == traits_t::eof();
120 }
121
140 template <std::ranges::forward_range range_type>
141 requires std::ranges::borrowed_range<range_type>
142 auto write_range(range_type && rng)
143 {
144 using sen_t = std::ranges::sentinel_t<range_type>;
145 using it_t = std::ranges::iterator_t<range_type>;
146
147 it_t it = std::ranges::begin(rng);
148 sen_t end = std::ranges::end(rng);
149
150 while (it != end)
151 {
152 size_t const buffer_space = stream_buf->epptr() - stream_buf->pptr();
153
154 if constexpr (std::ranges::sized_range<range_type>)
155 {
156 size_t const characters_to_write = std::min<size_t>(std::ranges::distance(it, end), buffer_space);
157 auto copy_res = std::ranges::copy_n(it, characters_to_write, stream_buf->pptr());
158 it = copy_res.in;
159 stream_buf->pbump(characters_to_write);
160 }
161 else
162 {
163 size_t i = 0;
164 for (; it != end && i < buffer_space; ++it, ++i)
165 *stream_buf->pptr() = *it;
166 stream_buf->pbump(i);
167 }
168
169 if (it == end) // no more characters to write
170 return it;
171
172 // Push one more character and flush
173 if (stream_buf->overflow(*it) == traits_t::eof())
174 {
175 // LCOV_EXCL_START
176 throw std::ios_base::failure{"Cannot write to output stream (reached traits::eof() condition)."};
177 // LCOV_EXCL_STOP
178 }
179
180 ++it; // drop 1 character that has been written in overflow()
181 }
182
183 return it;
184 }
185
187 // overload for non-std::ranges::borrowed_range types that return void
188 template <std::ranges::forward_range range_type>
189 void write_range(range_type && rng)
190 {
191 write_range(rng); // lvalue is always a safe range. return value is ignored because iterator would be dangling
192 }
194
199 template <typename number_type>
200 requires std::is_arithmetic_v<number_type>
201 auto write_number(number_type num)
202 {
203 if (stream_buf->epptr() - stream_buf->pptr() > 300) // enough space for any number, should be likely
204 {
205 auto res = std::to_chars(stream_buf->pptr(), stream_buf->epptr(), num);
206 stream_buf->pbump(res.ptr - stream_buf->pptr()); // advance pptr
207 }
208 else
209 {
210 std::array<char, 300> arithmetic_buffer{};
211 auto res = std::to_chars(&arithmetic_buffer[0], &arithmetic_buffer[0] + sizeof(arithmetic_buffer), num);
212 write_range(std::ranges::subrange<char *, char *>(&arithmetic_buffer[0], res.ptr));
213 }
214 }
215
220 void write_end_of_line(bool const add_cr)
221 {
222 if (add_cr)
223 *this = '\r';
224 *this = '\n';
225 }
226};
227
228} // namespace seqan3::detail
T begin(T... args)
The <charconv> header from C++17's standard library.
T copy_n(T... args)
T end(T... args)
SeqAn specific customisations in the standard namespace.
Provides seqan3::detail::stream_buffer_exposer.
T to_chars(T... args)
Hide me