1. Synopsis

namespace strf {

template <typename T, unsigned Log2BufferSpace>
class output_buffer;

constexpr std::size_t min_destination_buffer_size = …​; // >= 64

template <typename CharT>
using destination = output_buffer<CharT, …​>;

template <typename CharT>
class basic_cstr_destination;

template <typename CharT>
class array_destination;

template <typename CharT>
class discarder;

template <typename CharT>
CharT* garbage_buff();

template <typename CharT>
CharT* garbage_buff_end();

using u8cstr_destination  = basic_cstr_destination<char8_t>;
using cstr_destination    = basic_cstr_destination<char>;
using u16cstr_destination = basic_cstr_destination<char16_t>;
using u32cstr_destination = basic_cstr_destination<char32_t>;
using wcstr_destination   = basic_cstr_destination<wchar_t>;

} // namespace strf

2. Class template output_buffer

2.1. Synopsis

namespace strf {

template <typename T, unsigned Log2BufferSpace>
class output_buffer: output_buffer<T, Log2BufferSpace - 1>
{
public:
    static constexpr std::size_t    min_space_after_recycle  = 1 << Log2BufferSpace;
    static constexpr std::ptrdiff_t min_sspace_after_recycle = 1 << Log2BufferSpace;

protected:
    using output_buffer<T, Log2BufferSpace - 1>::output_buffer;
};

template <typename T>
class output_buffer<T, 0>
{
public:
    static constexpr std::size_t    min_space_after_recycle = 1;
    static constexpr std::ptrdiff_t min_sspace_after_recycle = 1;
    using value_type = T;

    output_buffer(const output_buffer&) = delete;
    output_buffer(output_buffer&&) = delete;
    output_buffer& operator=(const output_buffer&) = delete;
    output_buffer& operator=(output_buffer&&) = delete;

    virtual ~output_buffer() = default;

    T* buffer_ptr() const noexcept;
    T* ptr() const noexcept;

    T* buffer_end() const noexcept;
    T* end() const noexcept;

    std::size_t buffer_space() const noexcept;
    std::size_t space() const noexcept;

    std::ptrdiff_t buffer_sspace() const noexcept;
    std::ptrdiff_t sspace() const noexcept;

    bool good() const noexcept;
    void advance_to(T* p);
    void advance();
    void advance_count(std::integral auto n);
    void ensure(std::integral auto s);
    void flush();

    void write(const T* data, std::integral auto count);

    virtual void recycle() = 0;

protected:

    output_buffer(T* buff, T* buff_end);

    output_buffer(T* buff, std::ptrdiff_t buff_size);

    void set_buffer_ptr(T* p) noexcept;
    void set_buffer_ptr(T* p) noexcept;

    void set_buffer_end(T* e) noexcept;
    void set_buffer_end(T* e) noexcept;

    void set_good(bool g) noexcept;

    virtual void do_write(const T* data, std::size_t count);
};

// global functions

template <typename T>
void put(output_buffer<T, 0>& dest, T value);

} // namespace strf

2.2. Member types

using value_type = T;

2.3. Public member functions

T* buffer_ptr() const noxcept;
T* ptr() const noxcept;
Return

The memory position where the content shall be written.

T* buffer_end() const noxcept;
T* end() const noxcept;
Return

The end of memory position where the content shall be written. Dereferencing buffer_end() has undefined behaviour.

std::size_t buffer_space() const noexcept;
std::size_t space() const noexcept;

std::ptrdiff_t_t buffer_sspace() const noexcept;
std::ptrdiff_t_t sspace() const noexcept;
Return

buffer_end() - buffer_ptr()

void flush();
Effect

Calls recycle()

virtual void recycle() = 0;
Posconditions
void ensure(std::integral auto s)
Effect

Calls recycle() if buffer_sspace() < s.

Precondition

s <= min_sspace_after_recycle

Postcondition

buffer_space() >= s

void advance_to(T* p)
Effect

Advance the buffer’s pointer to p.

Precondition

buffer_ptr() <= p && p <= buffer_end()

Postcondition

buffer_ptr() == p

void advance()
Effect

Equivalent to advance(1)

Precondition

buffer_ptr() != buffer_end()

void advance(std::integral auto n)
Effect

Equivalent to advance_to(buffer_ptr() + n)

Precondition

0 <= n && n <= buffer_space()

bool good() const;
Return

The state of this object.

Semantincs

good() == false means that writting anything on buffer_ptr(), and calling advance_to and recycle() has no relevant side effect besides their postconditions.

Note

The range [ buffer_ptr(), buffer_end() ) shall aways be a valid accessible memory, even when good() returns false.

void write(const T* data, std::integral auto count);
Effect

None if count ⇐ 0 is true. Otherwise, if count <= buffer_space() is true, copy count elements of of the array pointer by data into buffer_ptr() and calls advance(count). Otherwise, calls do_write(data, count).

2.4. Protected Member functions

output_buffer(T* buff_, T* buff_end_)
Preconditions
  • buff_ <= buff_end_

  • The range [ buff_, buff_end_ ) must be an accessible memory area.

Posconditions
output_buffer(T* buff_, std::ptrdiff_t buff_size_)
Preconditions
  • buff_size_ \>= 0

  • The range [ buff_, `buff_ + n ` ) must be an accessible memory area.

Posconditions
void set_buffer_ptr(T* p) noexcept;
void set_ptr(T* p) noexcept;
Postconditions

buffer_ptr() == p

void set_buffer_end(T* e) noexcept;
void set_end(T* e) noexcept;
Postconditions

buffer_end() == e

void set_good(bool g) noexcept;
Postconditions

good() == g

virtual void do_write(const T* data, std::size_t count);
Effect

Writes the first count elements of the array pointed by data into this object, calling recycle() how many time it is necessary.

Note

This function is made virtual so that any derived classes can override it with an optimized version.

2.5. Global functions

template <typename T>
void put(output_buffer<T, 0>& dest, T value);
Effect
if (dest.buffer_space() == 0) {
    dest.recycle();
}
*dest.buffer_ptr() = value;
dest.advance();

3. Type alias template destination

namespace strf {

constexpr unsigned    log2_min_destination_buffer_size = …​; // >= 6
constexpr std::size_t      min_destination_buffer_size = …​; // >= 64

template <typename CharT>
using destination = output_buffer<CharT, log2_min_destination_buffer_size>;

} // namespace strf
  • log2_min_destination_buffer_size is an implementation-defined value that is greater than or equal to 6.

  • min_destination_buffer_size is equal to (std::size_t)1 << log2_min_destination_buffer_size

4. Class template basic_cstr_destination

namespace strf {

template <typename CharT>
class basic_cstr_destination final: public output_buffer<CharT, log2_garbage_buff_size> {
public:
    basic_cstr_destination(CharT* dest, CharT* dest_end) noexcept;

    basic_cstr_destination(CharT* dest, std::integral auto len) noexcept;

    template <std::size_t N>
    basic_cstr_destination(CharT (&dest)[N]) noexcept;

    basic_cstr_destination(const basic_cstr_destination&) = delete;
    basic_cstr_destination(basic_cstr_destination&&) = delete;
    basic_cstr_destination& operator=(const basic_cstr_destination&) = delete;
    basic_cstr_destination& operator=(basic_cstr_destination&&) = delete;

    basic_cstr_destination() override = default;

    void recycle() noexcept override;

    struct result {
        CharT* ptr;
        bool truncated;
    };

    result finish() noexcept;
};

} // namespace strf

4.1. Public member functions

basic_cstr_destination(CharT* dest, CharT* dest_end) noexcept;
Precondition

dest < dest_end

Postconditions
basic_cstr_destination(CharT* dest, std::integral auto dest_size) noexcept;
Precondition

dest_size > 0

Postconditions
template <std::size_t N>
basic_cstr_destination(CharT (&dest)[N]) noexcept;
Postconditions
void recycle() noexcept;
Postconditions
result finish() noexcept;
Effects
  • Assign to '\0' the position after the last written character in memory area used to initialize this object and set this object into "bad" state.

Return value
  • result::truncated is true if recycle or finish has ever been called in this object.

  • result::ptr points to the termination character '\0'.

Postconditions

5. Class template array_destination

namespace strf {
template <typename CharT>
class array_destination final : public output_buffer<CharT, log2_garbage_buff_size> {
public:
    template <std::size_t N>
    array_destination(CharT (&dest)[N]) noexcept;
    array_destination(CharT* dest, CharT* dest_end) noexcept;
    array_destination(CharT* dest, std::integral auto dest_size) noexcept;

    array_destination(const array_destination&) = delete;
    array_destination(array_destination&&) = delete;
    array_destination& operator=(const array_destination&) = delete;
    array_destination& operator=(array_destination&&) = delete;

    ~array_destination() override = default;

    void recycle() noexcept override;

    struct result {
        CharT* ptr;
        bool truncated;
    };

    result finish() noexcept;
};
} // namespace strf

5.1. Public member functions

template <std::size_t N>
array_destination(CharT (&dest)[N]) noexcept;
Postconditions
array_destination(CharT* dest, CharT* dest_end) noexcept;
Precondition

dest < dest_end

Postconditions
array_destination(CharT* dest, std::integral auto dest_size) noexcept;
Precondition

dest_size >= 0

Postconditions
void recycle() noexcept;
Postconditions
result finish() noexcept;
Return value
  • result.truncated is true when recycle() or do_write(…​) has been previously called in this object, which means that the the range which with it was initialized is too small.

  • result::ptr is the one-past-the-end pointer of the characters written. However, when result.truncated is true, the number of characters written is unspecified.

6. Class template discarder

discarder it’s the library’s analogous to /dev/null. A discarder object ignores anything written to it.

namespace strf {

template <typename CharT>
class discarder final: public output_buffer<CharT, {log2_garbage_buff_size}>
{
public:
    discarder() noexcept;
    void recycle() noexcept override;
};

} // namespace strf
discarder() noexcept;
Postconditions
void recycle() noexcept;
Postconditions

7. Garbage buffer

These function templates return the begin and the end of a memory area that is never supposed to be read. It can be used when implementing a class that derives from output_buffer to set the buffer when the state is "bad".

constexpr unsigned log2_garbage_buff_size = …​;

Implementation-defined type that is greater than or equal to log2_min_destination_buffer_size;

constexpr std::size_t garbage_buff_size = (std::size_t)1 << log2_garbage_buff_size;
template <typename CharT>
CharT* garbage_buff() noexcept;

Returns the begin a memory area of garbage_buff_size elements that are never supposed to be read.

template <typename CharT>
CharT* garbage_buff_end() noexcept;

Returns garbage_buff() + garbage_buff_size