namespace strf {

template <std::size_t CharSize>
constexpr std::size_t min_size_after_recycle();

template <std::size_t CharSize>
using underlying_char_type = /* ... */;

template <std::size_t CharSize>
class underlying_outbuff
{ /* ... */ };

template <typename CharT>
class basic_outbuff: public underlying_outbuff<sizeof(CharT)>
{ /* ... */ };

template <typename CharT>
class basic_outbuff_noexcept: public basic_outbuff<CharT>
{ /* ... */ };

template <std::size_t CharSize>
void put(underlying_outbuff<CharSize>& ob, underlying_char_type<CharSize> c);

template <typename CharT>
void put(basic_outbuff<CharT>& ob, CharT c);

template <typename CharT>
class basic_cstr_writer final: public basic_outbuff_noexcept<CharT>
{ /* ... */};

template <typename CharT>
class discarded_outbuff final: public basic_outbuff_noexcept<CharT>
{ /* ... */};

template <typename CharT>
CharT* outbuff_garbage_buf();

template <typename CharT>
CharT* outbuff_garbage_buf_end();

using bin_outbuff     = basic_outbuff<std::byte>;
using u8outbuff       = basic_outbuff<char8_t>;
using outbuff         = basic_outbuff<char>;
using u16outbuff      = basic_outbuff<char16_t>;
using u32outbuff      = basic_outbuff<char32_t>;
using woutbuff        = basic_outbuff<wchar_t>;

using u8cstr_writer  = basic_cstr_writer<char8_t>;
using cstr_writer    = basic_cstr_writer<char>;
using u16cstr_writer = basic_cstr_writer<char16_t>;
using u32cstr_writer = basic_cstr_writer<char32_t>;
using wcstr_writer   = basic_cstr_writer<wchar_t>;

} // namespace strf

1. Function template min_size_after_recycle

template <std::size_t CharSize>
constexpr std::size_t min_size_after_recycle();
Return value

Implementation-defined value greater than or equal to 64.

2. Template alias underlying_char_type

template <std::size_t CharSize>
using underlying_char_type = /*see below*/;
Same as
  • std::uint8_t if CharSize == 1

  • char16_t if CharSize == 2

  • char32_t if CharSize == 4

It is undefined for any other CharSize value.

3. Class template underlying_outbuff

3.1. Synopsis

namespace strf {

template <std::size_t CharSize>
class underlying_outbuff;
{
public:

    using char_type = underlying_char_type<CharSize>;

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

    virtual ~underlying_outbuff() = default;

    char_type* pointer() const noexcept;
    char_type* end() const noexcept;
    std::size_t size() const noexcept;
    bool good() const noexcept;
    void advance_to(char_type* p);
    void advance(std::size_t n);
    void require(std::size_t s);

    virtual bool recycle() = 0;

protected:

    underlying_outbuff(char_type* pointer_, char_type* end_);

    underlying_outbuff(char_type* pointer_, std::size_t n);

    void set_pointer(char_type* p) noexcept;
    void set_end(char_type* e) noexcept;
    void set_good(bool g) noexcept;
};

// global functions

template <std::size_t CharSize>
void put( underlying_outbuff<CharSize>& ob
        , underlying_char_type<CharSize> ch );

} // namespace strf

3.2. Member types

using char_type = underlying_char_type<CharSize>;

3.3. Public member functions

char_type* pointer() const noxcept;
Return

The memory position where the content shall be written.

char_type* end() const noxcept;
Return

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

std::size_t size() const noexcept;
Return

end() - pointer()

virtual void recycle() = 0;
Posconditions
  • size() >= min_size_after_recycle<CharSize>()

  • The range [ pointer(), end() ) is valid accessible memory area

  • If the return value of good() was false before this call to recycle(), then good() remains returning false.

void require(std::size_t s)
Effect

Calls recycle() if size() < s.

Precondition

s <= min_size_after_recycle<CharSize>()

Postcondition

size() >= s

void advance_to(char_type* p)
Effect

Advance the buffer’s pointer to p.

Precondition

pointer() <= p && p <= end()

Postcondition

pointer() == p

void advance(std::size_t n)
Effect

Same as advance_to(pointer() + n)

Precondition

n <= size()

void advance()
Effect

Same as advance_to(1)

Precondition

pointer() != end()

bool good() const;
Return

The state of this object. If the return value is false, then it means that calling advance of advance_to has no relevant side effect because the content written in the buffer will not be read anymore.

Note

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

3.4. Protected Member functions

underlying_outbuff(CharT* pointer_, CharT* end_)
Preconditions
  • pointer_ <= end_

  • The range [ pointer_, end_ ) must be an accessible memory area.

Posconditions
  • pointer() == pointer_

  • end() == end_

  • good() == true

underlying_outbuff(CharT* pointer_, std::size_t n)
Preconditions
  • The range [ pointer_, `pointer_ + n ` ) must be an accessible memory area.

Posconditions
  • pointer() == pointer_

  • end() == pointer_ + n

  • good() == true

void set_pointer(CharT* p) noexcept
Postconditions

pointer() == p

void set_end(CharT* e) noexcept
Postconditions

end() == e

void set_good(bool g) noexcept
Postconditions

good() == g

3.5. Global functions

template <std::size_t CharSize>
void put( underlying_outbuff<CharSize>& ob
        , underlying_char_type<CharSize> ch );
Effect

Same as:

if (ob.size() == 0) {
    ob.recycle();
}
*ob.pointer() = ch;
ob.advance();

4. Class template basic_outbuff

namespace strf {

template <typename CharT>
class basic_outbuff: private underlying_outbuff<sizeof(CharT)>
{
public:
    using char_type = CharT;
    basic_outbuff(const basic_outbuff&) = delete;
    basic_outbuff(basic_outbuff&&) = delete;
    basic_outbuff& operator=(const basic_outbuff&) = delete;
    basic_outbuff& operator=(basic_outbuff&&) = delete;

    virtual ~basic_outbuff() = default;

    underlying_outbuff<sizeof(CharT)>& as_underlying() noexcept;
    const underlying_outbuff<sizeof(CharT)>& as_underlying() const noexcept;

    char_type* pointer() const noexcept;
    char_type* end() const noexcept;
    void advance_to(char_type* p);

    using underlying_outbuff<sizeof(CharT)>::size
    using underlying_outbuff<sizeof(CharT)>::advance
    using underlying_outbuff<sizeof(CharT)>::good
    using underlying_outbuff<sizeof(CharT)>::require
    using underlying_outbuff<sizeof(CharT)>::recycle

protected:

    basic_outbuff(char_type* pointer_, char_type* end_);
    basic_outbuff(char_type* pointer_, std::size_t n);

    void set_pointer(char_type* p) noexcept;
    void set_end(char_type* e) noexcept;

    using underlying_outbuff<sizeof(CharT)>::set_good;
};

// global type aliases

using outbuff      = basic_outbuff<char>;
using u8outbuff    = basic_outbuff<char8_t>;
using u16outbuff   = basic_outbuff<char16_t>;
using u32outbuff   = basic_outbuff<char32_t>;
using woutbuff     = basic_outbuff<wchar_t>;
using bin_outbuff  = basic_outbuff<std::byte>;

// global functions

template <typename CharT>
void put(basic_outbuff<CharT>& ob, CharT ch);

} // namespace strf

4.1. Public member functions

underlying_outbuff<sizeof(CharT)>& as_underlying() noexcept;
const underlying_outbuff<sizeof(CharT)>& as_underlying() const noexcept;
Return

*this

char_type* pointer() const noexcept;
Return

(CharT*) as_underlying().pointer();

char_type* end() const noexcept;
Return

(CharT*) as_underlying().end();

void advance_to(char_type* p);
Effect

Same as

as_underlying().advance_to((underlying_char_type<sizeof(CharT)>*)p)
Precondition

p <= end()

4.2. Public member functions inherited from private base underlying_outbuff<sizeof(CharT)>

    using underlying_outbuff<sizeof(CharT)>::size
    using underlying_outbuff<sizeof(CharT)>::advance
    using underlying_outbuff<sizeof(CharT)>::good
    using underlying_outbuff<sizeof(CharT)>::require
    using underlying_outbuff<sizeof(CharT)>::recycle

4.3. Protected member functions

basic_outbuff(char_type* pointer_, char_type* end_);
Effect

Initializes private base class underlying_outbuff<sizeof(CharT)> with pointer_ and end_ casted as underlying_char_type<sizeof(CharT)>*.

basic_outbuff(char_type* pointer_, std::size_t n);
Effect

Same as basic_outbuff(pointer_, pointer_ + n)

void set_pointer(char_type* p) noexcept;
Effect

Same as

as_underlying().set_pointer((underlying_char_type<sizeof(CharT)>*)p)
void set_end(char_type* e) noexcept;
Effect

Same as

as_underlying().set_end((underlying_char_type<sizeof(CharT)>*)e)
void set_good(bool g) noexcept;
Effect

Same as as_underlying().set_good(g)

4.4. Global functions

template <typename CharT>
void put(basic_outbuff<CharT>& ob, CharT ch);
Effect

Same as:

if (ob.size() == 0) {
    ob.recycle();
}
*ob.pointer() = ch;
ob.advance();

5. Class template basic_outbuff_noexcept

namespace strf {

template <typename CharT>
class basic_outbuff_noexcept: public basic_outbuff<CharT>
{
public:

    virtual void recycle() noexcept = 0;

protected:

    using basic_outbuff<CharT>::basic_outbuff;
};

// type aliases

using outbuff_noexcept      = basic_outbuff_noexcept<char>;
using u8outbuff_noexcept    = basic_outbuff_noexcept<char8_t>;
using u16outbuff_noexcept   = basic_outbuff_noexcept<char16_t>;
using u32outbuff_noexcept   = basic_outbuff_noexcept<char32_t>;
using woutbuff_noexcept     = basic_outbuff_noexcept<wchar_t>;
using bin_outbuff_noexcept  = basic_outbuff_noexcept<std::byte>;

} // namespace strf

6. Class template basic_cstr_writer

namespace strf {

template <typename CharT>
class basic_cstr_writer final: public basic_outbuff_noexcept<CharT>
{
public:

    basic_cstr_writer(CharT* dest, CharT* dest_end) noexcept;
    basic_cstr_writer(CharT* dest, std::size_t len) noexcept;
    template <std::size_t N>
    basic_cstr_writer(CharT (&dest)[N]) noexcept;

    void recycle() noexcept override;
    struct result
    {
        CharT* ptr;
        bool truncated;
    };
    result finish() noexcept;
};

} // namespace strf

6.1. Public member function

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

dest < dest_end

Postconditions
  • good() == true

  • pointer() == dest

  • end() == dest_end - 1

basic_cstr_writer(CharT* dest, std::size_t dest_size) noexcept;
Precondition

dest_size != 0

Postconditions
  • good() == true

  • pointer() == dest

  • end() == dest + dest_size - 1

template <std::size_t N>
basic_cstr_writer(CharT (&dest)[N]) noexcept;
Postconditions
  • good() == true

  • pointer() == dest

  • end() == dest + N - 1

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

7. Class template discarded_outbuff

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

namespace strf {

template <typename CharT>
class discarded_outbuff final: public basic_outbuff_noexcept<CharT>
{
public:
    discarded_outbuff() noexcept;
    void recycle() noexcept override;
};

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

8. 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 basic_outbuff to set the buffer when the state is "bad".

template <typename CharT>
CharT* garbage_buf() noexcept;
template <typename CharT>
CharT* garbage_buf_end() noexcept;