Loading...
Searching...
No Matches
fast_ostreambuf_iterator.hpp
Go to the documentation of this file.
// SPDX-FileCopyrightText: 2006-2025 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2025 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: BSD-3-Clause
#pragma once
#include <algorithm>
#include <array>
#include <cassert>
#include <iterator>
#include <ranges>
#include <seqan3/std/charconv>
#include <seqan3/io/stream/detail/stream_buffer_exposer.hpp>
namespace seqan3::detail
{
template <typename char_t, typename traits_t = std::char_traits<char_t>>
class fast_ostreambuf_iterator
{
private:
stream_buffer_exposer<char_t, traits_t> * stream_buf = nullptr;
public:
using difference_type = ptrdiff_t;
using value_type = char_t;
using reference = char_t;
using pointer = void;
using iterator_category = std::output_iterator_tag;
fast_ostreambuf_iterator() noexcept = default;
fast_ostreambuf_iterator(fast_ostreambuf_iterator const &) noexcept = default;
fast_ostreambuf_iterator(fast_ostreambuf_iterator &&) noexcept = default;
fast_ostreambuf_iterator & operator=(fast_ostreambuf_iterator const &) noexcept = default;
fast_ostreambuf_iterator & operator=(fast_ostreambuf_iterator &&) noexcept = default;
~fast_ostreambuf_iterator() noexcept = default;
explicit fast_ostreambuf_iterator(std::basic_streambuf<char_t, traits_t> & ibuf) :
stream_buf{reinterpret_cast<stream_buffer_exposer<char_t, traits_t> *>(&ibuf)}
{
assert(stream_buf != nullptr);
if (stream_buf->pptr() == stream_buf->epptr())
stream_buf->overflow(); // ensures that put area has space available
}
fast_ostreambuf_iterator & operator++()
{
return *this;
}
fast_ostreambuf_iterator & operator++(int)
{
return *this;
}
fast_ostreambuf_iterator & operator*()
{
return *this;
}
fast_ostreambuf_iterator & operator=(char_t const c)
{
assert(stream_buf != nullptr);
if (stream_buf->pptr() == stream_buf->epptr())
{
if (stream_buf->sputc(c) == traits_t::eof()) // overflow() [virtual], then write character
{
// LCOV_EXCL_START
throw std::ios_base::failure{"Cannot write to output stream (reached traits::eof() condition)."};
// LCOV_EXCL_STOP
}
}
else
{
*stream_buf->pptr() = c;
stream_buf->pbump(1); // advance pptr() in put area without any checks
}
return *this;
}
bool failed() const noexcept
{
return stream_buf->overflow() == traits_t::eof();
}
template <std::ranges::forward_range range_type>
requires std::ranges::borrowed_range<range_type>
auto write_range(range_type && rng)
{
using sen_t = std::ranges::sentinel_t<range_type>;
using it_t = std::ranges::iterator_t<range_type>;
it_t it = std::ranges::begin(rng);
sen_t end = std::ranges::end(rng);
while (it != end)
{
size_t const buffer_space = stream_buf->epptr() - stream_buf->pptr();
if constexpr (std::ranges::sized_range<range_type>)
{
size_t const characters_to_write = std::min<size_t>(std::ranges::distance(it, end), buffer_space);
auto copy_res = std::ranges::copy_n(it, characters_to_write, stream_buf->pptr());
it = copy_res.in;
stream_buf->pbump(characters_to_write);
}
else
{
size_t i = 0;
for (; it != end && i < buffer_space; ++it, ++i)
*stream_buf->pptr() = *it;
stream_buf->pbump(i);
}
if (it == end) // no more characters to write
return it;
// Push one more character and flush
if (stream_buf->overflow(*it) == traits_t::eof())
{
// LCOV_EXCL_START
throw std::ios_base::failure{"Cannot write to output stream (reached traits::eof() condition)."};
// LCOV_EXCL_STOP
}
++it; // drop 1 character that has been written in overflow()
}
return it;
}
// overload for non-std::ranges::borrowed_range types that return void
template <std::ranges::forward_range range_type>
void write_range(range_type && rng)
{
write_range(rng); // lvalue is always a safe range. return value is ignored because iterator would be dangling
}
template <typename number_type>
requires std::is_arithmetic_v<number_type>
auto write_number(number_type num)
{
if (stream_buf->epptr() - stream_buf->pptr() > 300) // enough space for any number, should be likely
{
auto res = std::to_chars(stream_buf->pptr(), stream_buf->epptr(), num);
stream_buf->pbump(res.ptr - stream_buf->pptr()); // advance pptr
}
else
{
std::array<char, 300> arithmetic_buffer{};
auto res = std::to_chars(&arithmetic_buffer[0], &arithmetic_buffer[0] + sizeof(arithmetic_buffer), num);
write_range(std::ranges::subrange<char *, char *>(&arithmetic_buffer[0], res.ptr));
}
}
void write_end_of_line(bool const add_cr)
{
if (add_cr)
*this = '\r';
*this = '\n';
}
};
} // namespace seqan3::detail
algorithm
array
cassert
charconv
The <charconv> header from C++17's standard library.
std::end
T end(T... args)
std::is_arithmetic_v
T is_arithmetic_v
iterator
std::min
T min(T... args)
std::to_chars
to_chars_result to_chars(char *first, char *last, floating_point_type value) noexcept
std::to_chars overload for floating point via a std::stringstream for default base = 10.
Definition charconv:187
stream_buffer_exposer.hpp
Provides seqan3::detail::stream_buffer_exposer.
Hide me