This document is still a work in progress.

1. facets_pack

1.1. Class template facets_pack

template <typename ... FPE>
class facets_pack;
Compile-time requirements

All types in FPE... satisfy FacetsPackElement.

Member functions

Constructors
constexpr facets_pack(const facets_pack& other);
Effects

Initializes each element in this object with the corresponding element in other

Compile-time requirements

std::is_copy_constructible_v<FPE> && ..., otherwise this constructor does not participate in overload resolution.

constexpr facets_pack(facets_pack&& other);
Effects

Initializes each element from the rvalue reference of the corresponding element in other

Compile-time requirements

std::is_move_constructible_v<FPE> && ..., otherwise this constructor does not participate in overload resolution.

constexpr explicit facets_pack(const FPE& ... fpe)
Effects

Initializes each element with the correspondig value in fpe...

Compile-time requirements

std::is_copy_constructible_v<FPE> && ..., otherwise this constructor does not participate in overload resolution.

template <typename... U>[br]
constexpr explicit facets_pack(U&&... u)
Effects

Initializes each element with the correspondig value in std::forward<U>(u)....

Compile-time requirements

This constructor does not participate in overload resolution, unless

  • sizeof...(U) == sizeof...(FPE), and

  • sizeof...(U) != 0, and

  • std::is_constructible_v<FPE, U&&> && ...

Assignment operators (deleted)
   facets_pack& operator=(const facets_pack&) = delete
   facets_pack& operator=(facets_pack&&) = delete;

Assignments are deleted because they seem unecessary and it’s unclear what would be the best implementation in the case there is any reference type in FPE....

1.2. Function template pack

template <typename ... T>
constexpr /* see below */ pack(const T& ... args)
Return type

facets_pack<std::remove_cv_t<std::remove_reference_t<T>>...>

Return value

A facets_pack object initialized with std::forward<T>(args)...

1.3. Function template get_facet

template <typename FCat, typename Tag, typename ... T>
constexpr decltype(auto) get_facet(const facets_pack<T...>& fp);
Effects

If has_facet<FCat, Tag>(fp) returns true then returns <<do_get_facet,do_get_facet<FCat, Tag>(fp), otherwise return FCat::get_default().

Compile-time requirements

FCat is a FacetCategory type.

1.4. Hypothetical function template fas_facet

This function template does not exists in this library. It is only documented to help to explain the get_facet function template.
template <typename FCat, typename Tag, typename FPE>
constexpr bool has_facet(const FPE& fpe)
Effects
  • If FPE is an instance of facets_pack, then returns wheter there is any elemente elm in fpe such that has_facet<FCat, Tag>(elm) is true.

  • If FPE is an instance of constrained_fpe<FPE, Filter>, then returns Filter<Tag>::value && has_facet<FCat, Tag>(fpe.get()).

  • If FPE is a Facet type, returns std::is_same_v<FCat, facet_category<FPE>>

Compile-time requirements

1.5. Hypothetical function template do_get_facet

This function template is not part of the library. It only is documented to help to explaine the get_facet function template
template <typename FCat, typename Tag, typename FPE>
constexpr decltype(auto) do_get_facet(const FPE& fpe);
Compile-time requirements

1.6. Class template constrained_fpe

template <template <class> class Filter, typename FPE>
class constrained_fpe;

The class template constrained_fpe is designed to be used in facets_pack. constrained_fpe<Filter, FPE> holds a value of FPE that will only be returned by get_facet<Category, Tag> if Filter<Tag>::value is true.

Compile-time requirements
  • For any type T, Filter<T> has a member variable value that is a static constexpr value whose type is implicitly convertible to bool

  • FPE satisfies ConstrainableFacetsPackElement.

Synopsis

namespace strf {

template <template <class> class Filter, typename FPE>
class constrained_fpe
{
public:
    // constructors
    constexpr constrained_fpe(const constrained_fpe&) = default;
    constexpr constrained_fpe(constrained_fpe&& other) = default;
    constexpr constrained_fpe(const FPE& f);

    // element access
    constexpr const FPE& get() const;

private:
    FPE element; // exposition only;
};

} // namespace strf

Member functions

Constructors
constexpr explicit constrained_fpe(const FPE& fpe);
Effect

Initializes the element of the constrained_fpe with fpe.

constexpr constrained_fpe(const constrained_fpe& other);
Effect

Initializes the element of the constrained_fpe from the const reference of the element of other.

Compile-time requirements

std::is_copy_constructible<FPE>::value is true.

constexpr constrained_fpe(constrained_fpe&& other);
Effect

Initializes the element of the constrained_fpe from the rvalue reference of element of other.

Compile-time requirements

std::is_move_constructible<FPE>::value is true.

Element access
constexpr const FPE& get() const;
Effect

Return the stored element;

1.7. Function template constrain

template <template <class> class Filter, typename T>
constexpr constrained_fpe<Filter, U> constrain(const T& arg);

constrain is just a syntatic sugar to create a constrained_fpe object.

Return type

constrained_fpe<Filter, U>, where U is std::remove_cv_t<std::remove_reference_t<T>>.

Return value

constrained_fpe<Filter, U>{ std::forward<T>(arg) }

Compile-time requirements

T is such that U satisfies FacetsPackElement.

1.8. Type requirement FacetsPackElement

A given type F satisfies FacetsPackElement if, and only if, one of the following conditions is true:

1.9. Type requirement ConstrainableFacetsPackElement

A given a type F is a ConstrainableFacetsPackElement if, and only if, one of the following conditions is true:

  • F is a Facet type and facet_category<F>::constrainable is true.

  • F is facets_pack<F2...> and all types in F2... are ConstrainableFacetsPackElement.

  • F is an instance of constrained_fpe.

1.10. Type requirement Facet

A given a type F satisfies Facet if all of the following conditions are met:

1.11. Type requirement FacetCagory

A given a type FCat satisfies FacetCategory if:

  • FCat has a static member function named get_default that takes no argument and whose return type is either F or const F&, where F is a type that satisfies the requirements associated to FCat.

  • FCat has a member named constrainable that is a static constexpr value convertible to bool. ( If this value is false then the facets associated FCat can not be constrained ).

1.12. Class template facet_traits

This class template provides the Facet informations. If you create a new facet, you can either define such informations as members of the facet, or specialize facet_traits.

template <typename F>
class facet_traits
{
public:
    using category = /* Facet::category or void */;
};

Public members

typename /* */ category;

Same as Facet::category if such member exist and is a type, otherwise it is an alias to void.

Specialization

template <typename F>
class facet_traits<const F>
{
public:
    using category = typename facet_traits<F>::category;
};

1.13. Type alias facet_category

facet_category is just a syntatic sugar:

template <typename Facet>
using facet_category = facet_traits<Facet>::typename category;

2. Requirements of printable types

This section provides what one needs to be known to add a new printable type or override an existing one.

2.1. Type requirement Printable

A type T is Printable if:

  • print_traits_of<T> is defined and is a PrintTraits type

  • print_traits_of<T>::forwarded_type is implicitly convertible from T

namespace strf {

struct print_traits_tag;

template <typename T> print_traits;

template <typename T> using print_traits_of = /* see below... */;

} // namespace strf

print_traits_of<T> is:

  • print_traits_of<std::remove_cvref<T>>, if T is a reference type or has any cv-qualifier

  • otherwise, it is Traits, when T is value_with_formatters<Traits, /*... */>

  • otherwise, it is print_traits<T> if such template specialization is defined

  • otherwise, it is decltype(tag_invoke(print_traits_tag{}, std::declval<T>()))

2.3. Type alias template forwarded_printable_type

namespace strf {

template <typename T>
using forwarded_printable_type = /* see below... */;

} // namespace strf

2.4. Type requirement PrintTraits

Given

Member types

T::forwarded_type

forwarded_type must be implicitly convertible from P, and must be copy-constructible. And its copy-constructor should be fast. ( forwarded_type is usually P or const P& )

forwarded_type is used intead of P as the storage type in some situations ( for example, the objects created by fmt and join ).

T::facet_tag

The type that is used as the tag type in get_facet. It shall not be a reference type, and shall not contain cv-qualifiers. Usually is it std::remove_cv_t<std::remove_reference<forwarded_type>>

T::fmt_type;

A type alias to a value_with_formatters<T, /*...*/> type. It is the return type of fmt(std::declval<P>())

Member static function templates

Given

  • T, a PrintTraits type.

  • CharT, a character type

  • fpack, a value of type facets_pack</*... */>

  • preview, an lvalue of type print_preview</*... */>

  • v, a value of type T::forwarded_type or T::fmt_type

T::template make_printer_input<CharT>(preview, fpack, v)
Return type

A PrinterInput type.

Return value

A value r such that &r.preview == &preview

2.5. Type requirements PrinterInput

Given

  • CharT, a character type

  • Preview, an instance of the print_preview class template

  • X, a PrinterInput type for types CharT and Preview

  • x, a value of type X

T::char_type

A type alias to CharT.

T::preview_type

A type alias to Preview.

T::printer_type

A type that is constructible from X and convertible to const printer<CharT>&, such that the sequence:

std::size_t s  = x.preview.get_size();
typename T::printer_type p{x};
std::size_t predicted_size = x.preview.get_size() - s;
std::size_t dest_size      = dest.size();
static_cast<const printer<CharT>&>(p).print_to(dest);

statisfies the following postconditions when Preview::size_required is true:

  • if predicted_size <= dest_size is true then dest.recycle() is not called.

x.preview

A lvalue reference of type Preview.

2.6. Function template make_default_printer_input

namespace strf {

template <typename CharT, typename Preview, typename FPack, typename Arg>
constexpr auto make_default_printer_input
    ( Preview& preview, const FPack& fp, const Arg& arg)
    noexcept(/* see below... */)
    -> /* see below... */

} // namespace strf

The expression make_default_printer_input<CharT>(preview, fp, arg) is equivalent to

print_traits_of<Arg>::template make_printer_input<CharT>(preview, fp, arg);

This facet category affects the return type and value of make_printer_input. This way, it enables the user change how a printable type is printed, by making the library an the alternative PrinterInput object. A facet of this category should aways be constrained to the printable type intended to be overriden.

namespace strf {

struct print_override_c {
    static constexpr bool constrainable = true;

    constexpr static no_print_override get_default() noexcept {
        return {};
    }
};

} // namespace strf

Struct no_print_override

no_print_override is the default facet of print_override_c category.

namespace strf {

struct no_print_override {
    using category = print_override_c;

    template <typename CharT, typename Preview, typename FPack, typename Arg>
    constexpr static auto make_printer_input(Preview& preview, const FPack& fp, Arg&& arg)
        noexcept(noexcept(make_default_printer_input<CharT>(preview, fp, arg)))
    {
        return make_default_printer_input<CharT>(preview, fp, arg);
    }
};

} // namespace strf

2.8. Function template make_printer_input

namespace strf {

template <typename CharT, typename Preview, typename FPack, typename Arg>
constexpr auto make_printer_input(Preview& preview, const FPack& fp, const Arg& arg)
{
    auto tag = typename print_traits_of<Arg>::facet_tag;
    auto f = get_facet<print_override_c, tag>(fp);
    return f.template make_printer_input<CharT>(preview, fp, arg);
}

} // namespace strf

2.9. Type alias template printer_type

namespace strf {

template <typename CharT, typename Preview, typename FPack, typename Arg>
using printer_input_type = decltype
    ( make_printer_input<CharT>( std::declval<Preview&>()
                               , std::declval<const FPack&>()
                               , std::declval<Arg>() ) );

template <typename CharT, typename Preview, typename FPack, typename Arg>
using printer_type = typename printer_input_type<CharT, Preview, FPack, Arg>::printer_type;

} // namespace strf

2.10. Class template printer

namespace strf {

template <typename CharT>
class printer {
public:
    using char_type = CharOut;
    virtual ~printer() {}
    virtual void print_to(basic_outbuff<CharT>&) const = 0;
};

} // namespace strf
namespace strf {

enum class preview_width: bool { no = false, yes = true };
enum class preview_size : bool { no = false, yes = true };

template <preview_size SizeRequired, preview_width WidthRequired>
class print_preview
    : public size_preview<static_cast<bool>(SizeRequired)>
    , public width_preview<static_cast<bool>(WidthRequired)>
{
public:

    static constexpr bool size_required = static_cast<bool>(SizeRequired);
    static constexpr bool width_required = static_cast<bool>(WidthRequired);
    static constexpr bool nothing_required = ! size_required && ! width_required;

    constexpr print_preview() noexcept = default;
    constexpr explicit print_preview(width_t initial_width) noexcept;
};

} // namespace strf

Constructors

constexpr print_preview() noexcept;
Effect

Default-construct each of the base classes.

constexpr explicit print_preview(width_t initial_width) noexcept;
Compile-time requirement

WidthRequired is preview_width::yes, otherwise this constructor does not participate in overload resolution.

Effect

Initializes width_preview base with initial_width.

2.12. Class template size_preview

namespace strf {
template <bool Active>
class size_preview
{
public:
    explicit constexpr size_preview() noexcept;
    explicit constexpr size_preview(std::size_t initial_size) noexcept;

    constexpr void add_size(std::size_t) noexcept;
    constexpr std::size_t get_size() const noexcept;
};
} // namespace strf

Member functions

explicit constexpr size_preview() noexcept;
Postcondition

get_size() == 0

explicit constexpr size_preview(std::size_t initial_size) noexcept;
Compile-time requirement

Active is true, otherwise this constructor does not participate in overload resolution.

Postcondition

get_size() == initial_size

constexpr void add_size(std::size_t s) noexcept;
Postcondition
When Active is false

None

When Active is true

(get_size() - previous_size == s), where previous_size is the return value of get_size() before this call.

constexpr void get_size() const noexcept;
Return value
When Active is false

0 (always)

When Active is true

The internally stored size value.

2.13. Class template width_preview

namespace strf {
template <bool Active>
class width_preview
{
public:
    constexpr width_preview() noexcept;
    explicit constexpr width_preview(width_t initial_width) noexcept;
    constexpr void subtract_width(width_t) noexcept;
    constexpr void checked_subtract_width(std::ptrdiff_t w) noexcept;
    constexpr void clear_remaining_width() noexcept;
    constexpr width_t remaining_width() const noexcept;
}
} // namespace strf

Member functions

constexpr width_preview() noexcept;
Postcondition

remaining_width() == 0

constexpr width_preview(width_t initial_width) noexcept;
Compile-time requirement

Active is true, otherwise this constructor does not participate in overload resolution.

Postcondition

remaining_width() == initial_width

void subtract_width(width_t w) noexcept;
Postcondition
When Active is false

None

When Active is true
remaining_width() == previous_w - w

where previous_w is the return value of remaining_width() before this call.

void checked_subtract_width(width_t w) noexcept;
Postcondition
When Active is false

None

When Active is true
remaining_width() == (w < previous_w ? previous_w - w : 0)

where previous_w is the return value of remaining_width() before this call.

void checked_subtract_width(std::ptrdiff_t w)
Postcondition
When Active is false

None

When Active is true
remaining_width() == (w < previous_w.ceil() ? previous_w - (std::int16_t)w : 0)

where previous_w is the return value of remaining_width() before this call.

3. Format functions

3.1. Global format functions

namespace strf {
inline namespace format_functions {

constexpr /*…​*/ hex {};
constexpr /*…​*/ dec {};
constexpr /*…​*/ oct {};
constexpr /*…​*/ bin {};
constexpr /*…​*/ fixed {};
constexpr /*…​*/ sci {};
constexpr /*…​*/ gen {};
constexpr /*…​*/ multi {};
constexpr /*…​*/ conv {};
constexpr /*…​*/ sani {};
constexpr /*…​*/ right {};
constexpr /*…​*/ left {};
constexpr /*…​*/ center {};
constexpr /*…​*/ split {};

} // inline namespace format_functions
} // namespace strf

The format_functions inline namespace contains callable objects that work as alias to format functions

Expression Equivalent Expression

left(arg, width)

fmt(arg) < width

right(arg, width)

fmt(arg) > width

center(arg, width)

fmt(arg) ^ width

split(arg, width)

fmt(arg) % width

left(arg, width, ch)

fmt(arg).fill(ch) < width

right(arg, width, ch)

fmt(arg).fill(ch) > width

center(arg, width, ch)

fmt(arg).fill(ch) ^ width

split(arg, width, ch)

fmt(arg).fill(ch) % width

bin(arg)

fmt(arg).bin()

dec(arg)

fmt(arg).oct()

oct(arg)

fmt(arg).dec()

hex(arg)

fmt(arg).hex()

sci(arg)

fmt(arg).sic()

fixed(arg)

fmt(arg).fixed()

gen(arg)

fmt(arg).gen()

sci(arg, precision)

fmt(arg).sic().p(precision)

fixed(arg, precision)

fmt(arg).fixed().p(precision)

gen(arg, precision)

fmt(arg).gen().p(precision)

multi(arg, count)

fmt(arg).multi(count)

sani(arg, enc)

fmt(arg).sani(enc)

conv(arg, enc)

fmt(arg).conv(enc)

sani(arg)

fmt(arg).sani()

conv(arg)

fmt(arg).cont()

3.2. Callable object fmt

namespace strf {

template <typename T>
using fmt_value_type = typename fmt_type<T>::value_type;

constexpr struct /*…​*/ {
    template <typename T>
    constexpr fmt_type<T> operator()(T&& value) const
        noexcept(noexcept(fmt_type<T>fmt_value_type<T>{(T&&)value}}))
    {
        return fmt_type<T>{fmt_value_type<T>{(T&&)value}};
    }
} fmt;

} // namespace strf

3.3. Type alias template fmt_type

namespace strf {

template <typename T>
using fmt_type = /*…​*/;

} // namespace strf

fmt_type<T> is:

fmt_type<T> is always expected to be an instance of value_with_formatters class template.

3.4. Class template value_with_formatters

namespace strf {

template <typename ValueType, class... Fmts>
class value_with_formatters;

} // namespace strf
Compile-time requirements
  • All types in Fmt... satisfy Formatter.

  • All types in Fmt... are different.

The purpose of the value_with_formatters class template is to aid the creation classes that contain format functions. The types of expressions like fmt("Hello"), fmt(55), *hex(55) > 20, etc, are all value_with_formatters instances. The ValueType template parameter holds the input type, and the types in Fmts... defines the format functions.

Synopsis

namespace strf {

template <typename ValueType, class... Fmts>
class value_with_formatters
    : public Fmts::template fn<value_with_formatters<ValueType, Fmts...>>...
{
public:

    constexpr value_with_formatters(const value_with_formatters&) = default;
    constexpr value_with_formatters(value_with_formatters&&) = default;
    constexpr value_with_formatters(const ValueType&);

    template <typename OtherValueType>
    constexpr value_with_formatters
        ( const ValueType&
        , const value_with_formatters<OtherValueType, Fmts...>& );

    template <typename OtherValueType>
    constexpr value_with_formatters
        ( const ValueType&
        , value_with_formatters<OtherValueType, Fmts...>&& );


    template <typename... OtherFmts>
    constexpr value_with_formatters(const value_with_formatters<ValueType, OtherFmts...>&);

    template <typename... OtherFmts>
    constexpr value_with_formatters(value_with_formatters<ValueType, OtherFmts...>&&);


    constexpr const ValueType& value() const;
};

} // namespace strf

To-do

3.5. Type requirement Formatter

A type Fmt is a Formatter if it has a member fn that is a type template with one template type parameter such that, given any types T and U:

  • Fmt::template fn<T> is well formed if T is value_with_formatters<ValueType, Fmts...>. In this case, note that Fmt is in Fmts... and T derives from Fmt::template fn<T>.

  • Fmt::template fn<T> is default constructible, assuming it is well formed.

  • Fmt::template fn<T> can be constructed from const Fmt::template fn<U>&, if both are well formed.

3.6. Formatter alignment_formatter

namespace strf {

template <bool HasAlignment>
struct alignment_formatter_q
{
    template <class T>
    using fn = alignment_formatter_fn<T, HasAlignment>;
};

using alignment_formatter       = alignment_formatter_q<true>;
using empty_alignment_formatter = alignment_formatter_q<false>;

} // namespace strf

alignment_formatter_fn

namespace strf {

template <class T, bool HasAlignment>
class alignment_formatter_fn;
{
public:
    // constructors
    constexpr alignment_formatter_fn() noexcept;

    template <typename U, bool B>
    constexpr explitic alignment_formatter_fn(const alignment_formatter_fn<U, B>& u) noexcept;

    // format functions
    constexpr T&& operator<(width_t width) && noexcept; // left
    constexpr T&& operator>(width_t width) && noexcept; // right
    constexpr T&& operator^(width_t width) && noexcept; // center
    constexpr T&& operator%(width_t width) && noexcept; // split, aka internal
    constexpr T&& fill(char32_t ch) && noexcept;

    // observers
    constexpr width_t width() const noexcept;
    constexpr text_alignment alignment() const noexcept;
    constexpr char32_t fill() const noexcept;
    constexpr alignment_format get_alignmet_format() const noexcept;
};

// alignment_formatter_fn<T, false> is an empty class
template <class T>
class alignment_formatter_fn<T, false>
{
    using converted_fmt = boost::mp_replace< T , alignment_formatter_q<false>
                                               , alignment_formatter_q<true> >;
public:
    // constructors
    constexpr alignment_formatter_fn() noexcept;

    template <typename U>
    constexpr explicit alignment_formatter_fn(const alignment_formatter_fn<U, false>&) noexcept;

    // observers
    constexpr width_t width() const noexcept;
    constexpr text_alignment alignment() const noexcept;
    constexpr char32_t fill() const noexcept;
    constexpr alignment_format get_alignmet_format() const noexcept;

    // format functions
    constexpr converted_fmt operator<(width_t width) const noexcept;
    constexpr converted_fmt operator>(width_t width) const noexcept;
    constexpr converted_fmt operator^(width_t width) const noexcept;
    constexpr converted_fmt operator%(width_t width) const noexcept;
    constexpr converted_fmt fill(char32_t ch) const noexcept;
};

} // namespace strf
Constructors
constexpr alignment_formatter_fn() noexcept;
Postconditions

get_alignmet_format() == alignment_format{}

template <typename U, bool B>
constexpr explitic alignment_formatter_fn(const alignment_formatter_fn<U, B>& u) noexcept;
Postconditions

get_alignmet_format() == u.get_alignmet_format()

Note

This function only participates in overload resolution if 'HasAlignment' is true or B is false

Observers
constexpr alignment_format get_alignmet_format() const noexcept;
Return value
  • alignment_format{}, when HasAlignment is false.

  • The value corresponding to the state of this object, when HasAlignment is true.

constexpr {width_t} width() const noexcept;
Return value

get_alignmet_format().width

constexpr text_alignment alignment() const noexcept;
Return value

get_alignmet_format().alignment

constexpr char32_t fill() const noexcept;
Return value

get_alignmet_format().fill

Format functions
constexpr /*return type */ operator<({width_t} width) /* qualifier */ noexcept;
Posconditions

The return value r satisfies:

  • r.width() == width

  • r.alignment == text_alignment::left

Return value
  • when HasAlignment is false: converted_fmt{static_cast<const T&>(*this)} < width.

  • when HasAlignment is true: std::move(static_cast<T&>(*this)).

constexpr /*return type */ operator>({width_t} width) /* qualifier */ noexcept;
Posconditions

The return value r satisfies:

  • r.width() == width

  • r.alignment() == text_alignment::right

Return value
  • when HasAlignment is false: converted_fmt{static_cast<const T&>(*this)} > width.

  • when HasAlignment is true: std::move(static_cast<T&>(*this)).

constexpr /*return type */ operator^({width_t} width) /* qualifier */ noexcept;
Posconditions

The return value r satisfies:

  • r.width() == width

  • r.alignment() == text_alignment::center

Return value
  • when HasAlignment is false: converted_fmt{static_cast<const T&>(*this)} ^ width.

  • when HasAlignment is true: std::move(static_cast<T&>(*this)).

constexpr /*return type */ operator%({width_t} width) /* qualifier */ noexcept;
Posconditions

The return value r satisfies:

  • r.width() == width

  • r.alignment() == text_alignment::split

Return value
  • when HasAlignment is false: converted_fmt{static_cast<const T&>(*this)} % width.

  • when HasAlignment is true: std::move(static_cast<T&>(*this)).

constexpr /*return type */ fill(char32_t ch) /* qualifier */ noexcept;
Posconditions

The return value r satisfies:

  • r.fill() == ch

Return value
  • when HasAlignment is false: converted_fmt{static_cast<const T&>(*this)}.fill(ch).

  • when HasAlignment is true: std::move(static_cast<T&>(*this)).

alignment_format

namespace strf {

enum class text_alignment {left, right, split, center};

struct alignment_format
{
    char32_t fill = U' ';
    width_t width = 0;
    text_alignment alignment = text_alignment::right;
};

constexpr bool operator==(alignment_format lhs, alignment_format rhs) noexcept;
constexpr bool operator!=(alignment_format lhs, alignment_format rhs) noexcept;
} // namespace strf

3.7. Formatter int_formatter

namespace strf {

template <class T, int Base>
class int_formatter_fn;

template <int Base>
struct int_formatter
{
    template <typename T>
    using fn = strf::int_formatter_fn<T, Base>;
};

} // namespace strf

int_formatter_fn

namespace strf {

struct int_format
{
    unsigned precision = 0;
    bool showbase = false;
    bool showpos = false;
};

constexpr bool operator==(int_format lhs, int_format rhs) noexcept;
constexpr bool operator!=(int_format lhs, int_format rhs) noexcept;

template <class T, int Base>
class int_formatter_fn
{
public:
    constexpr int_formatter_fn() noexcept;

    template <typename U, int OtherBase>
    constexpr int_formatter_fn(const int_formatter_fn<U, OtherBase> & u) noexcept;

    // observers
    constexpr int_format get_int_format() const noexcept;
    constexpr unsigned precision() const noexcept;
    constexpr bool showbase() const noexcept;
    constexpr bool showpos() const noexcept;
    constexpr static int base() noexcept;

    // format functions
    constexpr T&& p(unsigned precision) && noexcept; // set precision
    constexpr T&& operator+() && noexcept;           // show positive sign
    constexpr T&& operator*() && noexcept;           // show base
     constexpr T&& operator~() && noexcept;           // show base

    constexpr /* see below */ hex() && noexcept; // hexadecimal base
    constexpr /* see below */ dec() && noexcept; // decimal base
    constexpr /* see below */ oct() && noexcept; // octal base
    constexpr /* see below */ bin() && noexcept; // binary base
};
} // namespace strf
Observers
constexpr int_format get_int_format() const noexcept;
Return value

The value corresponding to the state of this object.

constexpr unsigned precision() const noexcept;
Return value

get_int_format().precision

constexpr showpos() const noexcept;
Return value

get_int_format().showpos

constexpr showbase() const noexcept;
Return value

get_int_format().showbase

constexpr static base() noexcept;
Return value

Base

Format functions
constexpr T&& p(unsigned precision) && noexcept;
Postconditions

precision() == precision

Return value

std::move(static_cast<T&>(*this))

constexpr T&& operator+() && noexcept;
Postconditions

showpos() == true

Return value

std::move(static_cast<T&>(*this))

constexpr T&& operator*() && noexcept;
Postconditions

showbase() == true

Return value

std::move(static_cast<T&>(*this))

constexpr /* see below */ hex() &&;     // hexadecimal base
constexpr /* see below */ dec() &&;     // decimal base
constexpr /* see below */ oct() &&;     // octal base
constexpr /* see below */ bin() &&;     // binary base
Return type
std::conditional_t< Base == NewBase
                  , T&&
                  , boost::mp_replace<T, int_formatter<Base>, int_formatter<NewBase> >

, where NewBase is equal to 10 in dec(), 16 in hex(), 8 in oct() and 2 in bin().

Return value
  • static_cast<ReturnType>(static_cast<T&>(*this)), where ReturnType is the return type;

3.8. Formatter float_formatter

namespace strf {

template <class T, float Base>
class float_formatter_fn;

template <float Base>
struct float_formatter
{
    template <typename T>
    using fn = float_formatter_fn<T, Base>;
};

} // namespace strf

float_formatter_fn

namespace strf {

template <typename T>
class float_formatter_fn
{
public:
    constexpr float_formatter_fn() noexcept;

    template <typename U>
    constexpr explicit float_formatter_fn(const float_format_fn<U>& other) noexcept;

    // observers
    constexpr float_format get_float_format() const noexcept;

    // format functions
    constexpr T&& operator+() && noexcept;
    constexpr T&& operator*() && noexcept;
    constexpr T&& p(unsigned precision) && noexcept;
    constexpr T&& gen() && noexcept;
    constexpr T&& sci() && noexcept;
    constexpr T&& fixed() && noexcept;
};
} // namespace strf
Constructors
constexpr float_formatter_fn() noexcept;
Postconditions

get_float_format() == float_format{}

template <typename U>
constexpr explicit float_formatter_fn(const float_formatter_fn<U>& other) noexcept;
Postconditions

get_float_format() == other.get_float_format()

Format functions
constexpr T&& operator+() && noexcept;
Postconditions

get_float_format().showpos == true

Return value

static_cast<T&&>(static_cast<T&>(*this))

constexpr T&& operator*() && noexcept;
Postconditions

get_float_format().showpoint == true

Return value

static_cast<T&&>(static_cast<T&>(*this))

constexpr T&& p(unsigned precision) && noexcept;
Postconditions

get_float_format().precision == precision

Return value

static_cast<T&&>(static_cast<T&>(*this))

constexpr T&& gen() && noexcept;
Postconditions

get_float_format().notation = float_notation::general

Return value

static_cast<T&&>(static_cast<T&>(*this))

constexpr T&& sci() && noexcept;
Postconditions

get_float_format().notation = float_notation::scientific

Return value

static_cast<T&&>(static_cast<T&>(*this))

constexpr T&& fixed() && noexcept;
Postconditions

get_float_format().notation = float_notation::fixed

Return value

static_cast<T&&>(static_cast<T&>(*this))

float_format

namespace strf {

enum class float_notation{fixed, scientific, general};

struct float_format
{
    unsigned precision = (unsigned)-1;
    float_notation notation = float_notation::general;
    bool showpoint = false;
    bool showpos = false;
};

constexpr bool operator==(float_format lhs, float_format rhs) noexcept;
constexpr bool operator!=(float_format lhs, float_format rhs) noexcept;
} // namespace strf
notation
  • float_notation::fixed: Prints like 123.45

  • float_notation::scientific: Prints like 1.2345e+02

  • float_notation::general: When precision is (unsigned)-1, prints in the scientfic notation if it is shorter than the fixed notation. When precision is different than (unsigned)-1, does like in std::printf: uses the scientfic notation if the exponent is less than -4 or greater than or equal to the precision. Trailing fractional zeros are not printed.

precision

When notation == float_notation::general, the precision is the number of significant digits. Otherwise it is the number of fractional digits. precision == 0 has the same effect as precision == 1.

showpoint

Prints the decimal point even when there are no fractional digits.

showpos

Prints the positive sign '+' when the value is positive.

3.9. Formatter quantity_formatter

namespace strf {

struct quantity_formatter
{
    template <class T>
    using fn = quantity_formatter_fn<T>;
};

} // namespace strf

quantity_formatter_fn

namespace strf {

template <class T>
class quantity_formatter_fn
{
public:
    constexpr quantity_formatter_fn(std::size_t count) noexcept;
    constexpr quantity_formatter_fn() noexcept;

    template <typename U>
    constexpr explicit quantity_formatter_fn(const quantity_formatter_fn<U>& u) noexcept
        : _count(u.count())
    {
    }

    constexpr T&& multi(std::size_t count) && noexcept
    constexpr std::size_t count() const noexcept
};

} // namespace strf
Constructors
constexpr quantity_formatter_fn() noexcept;
Postconditions

count() == 1

template <typename U>
constexpr explicit quantity_formatter_fn(const quantity_formatter_fn<U>& u) noexcept;
Postconditions

count() == u.count()

Format functions
constexpr T&& multi(std::size_t count) && noexcept
Postconditions

count() == count

Return value

static_cast<T&&>(*this)

4. List of printable types

4.1. Strings

Types

const CharT*, std::string_view<CharT, Traits> and std::basic_string<CharT, Traits, Alloc>

where:

  • CharT is the character type. If it is not the same as the output character type ( defined by the destination ), then it is necessary to use the conv or sani format function.

  • Traits can be any type that satisfies CharTraits

  • Alloc can be any type that satisfies Allocator

Format functions

( in addition to alignment functions )

p(width_t limit)

Does not print the whole string if its width is greater than limit, but the greatest possible amount of its leading Unicode code points such that the width is not greater than limit.

template <typename Encoding> sanitize_from_encoding(Encoding enc)

Translates input string from enc to the output encoding. If the encodings are the same then sanitizes the input string.

sanitize_encoding()

Translates input string from the encoding associated to CharT to the output encoding. If these encodings are the same then sanitizes the input string.

template <typename Encoding> convert_from_encoding(Encoding enc)

Translates input string from enc to the output encoding, if these encodings are not the same. Otherwise, copies input string as it is.

convert_encoding()

Translates input string from the encoding associated to CharT to the output encoding, if these encodings are not the same. Otherwise, copies the input string as it is.

template <typename Encoding> sani(Encoding enc)

Equivanlent to sanitize_encoding(enc)

template <typename Encoding> conv(Encoding enc)

Equivanlent to convert_encoding(enc)

sani()

Equivalent to sanitize_encoding()

conv()

Equivalent to convert_encoding()

Example
auto str = strf::to_string(strf::center(u" Hello! ", 16, '*').conv());
assert(str == "**** Hello! ****");

See also the section about encoding conversion.

4.2. Single characters

Type

CharT, that is the output character type defined by the destination.

Format functions

( in addition to alignment functions )

multi(std::size_t count)

Prints the character count times. Default value is 1.

Facet categories

4.3. bool

Type

bool

Format functions

Alignment functions only.

Facet categories

4.4. const void*

Types

const void*

Format functions

The alignment functions only.

Facet categories

4.5. Integers

Types

short, int, long int, long long int, unsigned short, unsigned int, unsigned long int and unsigned long long int

Format functions

( in addition to alignment functions )

dec()

Use decimal base ( This is already the default, though )

hex()

Use hexadecimal base.

oct()

Use octal base.

bin()

Use binary base.

p(unsigned precision)

Ensures that at least precision digits are printed by adding extra zero leading digits if necessary.

operator+()

When in decimal base, prints the positive sign "+" when value is non negative. No effect for other bases.

operator*()

Prints the base indication ( "0x" for hexadecimal, "0" for octal and "0b" for binary ). No effect in decimal base.

operator~()

Equivalent to operator*(). Deprecated.

Facet categories

4.6. Floating Points

Types

float, double

Format functions

( In addition to the alignment functions )

operator+()

When in decimal base, prints the positive sign "+" if the value is non negative. No effect for other bases.

operator*()

Prints the decimal point even when there are no fractional digits.

operator~()

Equivalent to operator*(). Deprecated.

sci()

Prints in scientific notation, like this: "1.2345e+02".

fixed()

Prints in decimal notation, like this: "123.45".

gen()

This is the default notation. When precision is unspecified ( or equal to (unsigned)-1 ) prints in the scientfic notation if, and only if, it is shorter than the fixed notation. Otherwise ( when precision is specified ), does like in std::printf: uses the scientfic notation if the exponent is less than -4 or greater than or equal to the precision. Trailing fractional zeros are not printed.

hex()

Prints in hexadecimal notation, like this "-0x1.abcd123e+5"

p(unsigned precision)

If precision == (unsigned)-1, which is the default, then prints the minimal amount of digits so that value can be fully recovered by a parser. Otherwise, if notation is general, precision is the number of significant digits. Otherwise, it is the number of fractional digits. precision == 0 has the same effect as precision == 1.

Facet categories

4.7. Ranges

Without formatting

namespace strf {

template <typename Range>
/*...*/ range(const Range& r);

template <typename T, std::size_t N>
/*...*/ range(T (&array)[N]);

template <typename Iterator>
/*...*/ range(const Iterator& begin, const Iterator& end);

// With operation

template <typename Range, typename UnaryOperation>
/*...*/ range(const Range& r, UnaryOperation unary_op);

template <typename T, std::size_t N, typename UnaryOperation>
/*...*/ range(T (&array)[N], UnaryOperation unary_op);

template <typename Iterator, typename UnaryOperation>
/*...*/ range( const Iterator& begin
             , const Iterator& end
             , UnaryOperation unary_op );

// With separator:

template <typename Range, typename CharT>
/*...*/ separated_range(const Range& r, const CharT* separator);

template <typename T, std::size_t N, typename CharT>
/*...*/ separated_range(T (&array)[N], const CharT* separator);

template <typename Iterator, typename CharT>
/*...*/ separated_range( const Iterator& begin
                       , const Iterator& end
                       , const CharT* separator );

// With separator and operation

template <typename Range, typename CharT, typename UnaryOperation>
/*...*/ separated_range( const Range& r
                       , const CharT* separator
                       , UnaryOperation unary_op );

template <typename T, std::size_t N, typename CharT, typename UnaryOperation>
/*...*/ separated_range( T (&array)[N]
                       , const CharT* separator
                       , UnaryOperation unary_op );

template <typename Iterator, typename CharT, typename UnaryOperation>
/*...*/ separated_range( const Iterator& begin
                       , const Iterator& end
                       , const CharT* separator
                       , UnaryOperation unary_op );
} // namespace strf
Examples
int arr[3] = { 11, 22, 33 };

auto str = strf::to_string(strf::range(arr));
assert(str == "112233");

str = strf::to_string(strf::separated_range(arr, ", "));
assert(str == "11, 22, 33");

auto op = [](auto x){ return strf::join('(', +strf::fmt(x * 10), ')'); };

str = strf::to_string(strf::separated_range(arr, ", ", op));
assert(str == "(+110), (+220), (+330)");

With formatting

namespace strf {

template <typename Range>
/*...*/ fmt_range(const Range& r);

template <typename T, std::size_t N>
/*...*/ fmt_range(T (&array)[N], const Range& r);

template <typename Iterator>
/*...*/ fmt_range(const Iterator& begin, const Iterator& end);

// With separator

template <typename Range, typename CharT>
/*...*/ fmt_separated_range(const Range& r, const CharT* separator);

template <typename T, std::size_t N, typename CharT>
/*...*/ fmt_separated_range(T (&array)[N], const CharT* separator);

template <typename Iterator, typename CharT>
/*...*/ fmt_separated_range( const Iterator& begin
                           , const Iterator& end
                           , const CharT* separator );
} // namespace strf

Any format function applicable to the element type of the range can also be applied to the expression strf::fmt_range(/*...*/) or strf::fmt_separated_range(/*...*/). This way the format functions is applied to all elements:

Example 1
std::vector<int> vec = { 11, 22, 33 };
auto str1 = strf::to_string("[", +strf::fmt_separated_range(vec, " ;") > 4, "]");
assert(str1 == "[ +11 ; +22 ; +33]");
Example 2
std::vector<int> vec = { 11, 22, 33 };
auto str2 = strf::to_string
    ( "["
    , *strf::fmt_separated_range(vec, " / ").fill('.').hex() > 6,
    " ]");

assert(str2 == "[..0xfa / ..0xfb / ..0xfc]");

4.8. Joins

Without alignment

namespace strf {

template <typename ... Args>
/*...*/ join(const Args& ... args);

}

With alignment

You can apply the alignment format functions one the return type of join(args...)

auto str = strf::to_string
    ("---", strf::join("abc", "def", 123) > 15, "---");

assert(str == "---      abcdef123---");

The split_pos function specifies how many arguments go before the fill when the operator% is used.

str = strf::to_string
    ( strf::join('a', 'b', 'c', 'd', 'e', 'f').split_pos(2) % 10 );
assert(str == "ab    cdef");

The functions below provide an alternartive syntax to create aligned join. Their return type has the operator()(const Args& ... args) member function that receives the elements of the join.

namespace strf {

enum class text_alignment {left, right, split, center};

/* ... */ join_align( std::int16_t width
                    , text_alignment align
                    , char32_t fillchar = U' '
                    , std::ptrdiff_t split_pos = 0 );
/* ... */ join_center(int width, char32_t fillchar = U' ');
/* ... */ join_left(int width, char32_t fillchar = U' ');
/* ... */ join_right(int width, char32_t fillchar = U' ');
/* ... */ join_split(int width, int split_pos);
/* ... */ join_split( std::int16_t width
                    , char32_t fillchar
                    , std::ptrdiff_t split_pos );
}
Example
auto str = strf::to_string
    ("---", strf::join_right(15) ("abc", "def", 123), "---");
assert(str == "---      abcdef123---");

str = strf::to_string
    ("---", strf::join_center(15) ("abc", "def", 123), "---");
assert(str == "---   abcdef123   ---");

str = strf::to_string
    ( "---"
    , strf::join_left(15, U'.') ("abc", strf::right("def", 5), 123)
    , "---" );
assert(str == "---abc  def123....---");

str = strf::to_string
    ( "---"
    , strf::join_split(15, '.', 1) (strf::left("abc", 5), "def", 123)
    , "---" );
assert(str == "---abc  ....def123---");

4.9. Facets

It is possible to override facets to only a subset of the input arguments.

namespace strf {

template < typename FPack >
class inner_pack
{
public:
    template <typename... Args>
    /*...*/  operator()(const Args&... args) const;
    //...
};

template <typename ... Facets>
inner_pack</*...*/> with(const Facets&... facets);
Example 1
auto str = strf::to_string.with(strf::numpunct<10>(1))
    ( 10000
    , "  "
    , strf::hex(0x10000)
    , strf::with( strf::numpunct<10>(3)
                , strf::numpunct<16>(4).thousands_sep('\'') )
        ( "  { "
        , 10000
        , "  "
        , strf::hex(0x10000)
        , " }" ) );

assert(str == "1,0,0,0,0  10000  { 10,000  1'0000 }");
Example 2
auto fp = strf::pack
    ( strf::numpunct<10>(3)
    , strf::numpunct<16>(4).thousands_sep('\'') );

auto str = strf::to_string.with(strf::numpunct<10>(1))
    ( 10000
    , "  "
    , strf::hex(0x10000)
    , strf::with(fp)
        ( "  { "
        , 10000
        , "  "
        , strf::hex(0x10000)
        , strf::with
            (strf::numpunct<10>(2).thousands_sep('.'))
            ("  { ", 10000, " }")
        , " }" ) );

assert(str == "1,0,0,0,0  10000  { 10,000  1'0000  { 1.00.00 } }");

5. Destination types

The destination_no_reserve, destination_reserve_calc and destination_with_given_size class templates provide the basic usage syntax of the library:

syntax
  • no_reserve() always returns a destination_no_reserve object

  • reserve_calc() always returns a destination_reserve_calc object.

  • reserve(size) always returns a destination_with_given_size object.

  • The destination is an object whose type is an instance of one those three class templates.

5.1. Class template destination_no_reserve

template <typename OutbuffCreator, typename FPack = facets_pack<>>
class destination_no_reserve
Compile-time requirements

Synopsis

namespace strf {

template <typename OutbuffCreator, typename FPack>
class destination_no_reserve
{
public:
    using char_type = typename OutbuffCreator::char_type;

    // constructors
    template <typename... Args>
    constexpr destination_no_reserve(Args&&...);
    constexpr destination_no_reserve(const destination_no_reserve&);
    constexpr destination_no_reserve(destination_no_reserve&&);

    // facets
    template <typename... FPE>
    destination_no_reserve<OutbuffCreator, /*...*/> with(FPE&&...) const &;

    template <typename... FPE>
    destination_no_reserve<OutbuffCreator, /*...*/> with(FPE&&...) &&;

    // size reserve
    constexpr destination_calc_size<OutbuffCreator, FPack>
    reserve_calc() const &;

    constexpr destination_calc_size<OutbuffCreator, FPack>
    reserve_calc() &&;

    constexpr destination_with_given_size<OutbuffCreator, FPack>
    reserve(std::size_t) const &;

    constexpr destination_with_given_size<OutbuffCreator, FPack>
    reserve(std::size_t) &&;

    constexpr destination_no_reserve&  no_reserve() &;
    constexpr destination_no_reserve&& no_reserve() &&;
    constexpr const destination_no_reserve&  no_reserve() const &;
    constexpr const destination_no_reserve&& no_reserve() const &&;

    // printing
    template <typename... Args>
    /*...*/ operator()(const Args&...) const;

    template <typename... Args>
    /*...*/ tr(const char_type*, const Args&...) const;

    template <typename... Args>
    /*...*/ tr( const std::basic_string_view<char_type>&
              , const Args&...) const;

    template <typename... Args>
    /*...*/ tr( std::basic_string_view<char_type>
              , const Args&...) const;

private:
    OutbuffCreator _outbuff_creator; // exposition only
    FPack _fpack;                    // exposition only
};

} // namespace strf

Public member functions

Constructors
template <typename... Args>
constexpr destination_no_reserve(Args&&... args);
Compile-time requirements
  • FPack is DefaultConstructible

  • std::is_constructible<OutbuffCreator, Args...> is true, otherwise this constructor does not participate on overload resolution.

Effect
  • Initializes _outbuff_creator with std::forward<Args>(args)....

constexpr destination_no_reserve(const destination_no_reserve&) = default;

Copy constructor.

Compile-time requirements
constexpr destination_no_reserve(destination_no_reserve&&) = default;

Move constructor.

Facets
template <typename... FPE>
/* see below */ with(FPE&&...) const &;
Compile-time requirements
Return Type
destination_no_reserve< OutbuffCreator
                      , decltype(pack( std::declval<const FPack&>()
                                     , std::forward<FPE>(fpe)...) ) >
Effect

Creates a destination_no_reserve object whose _outbuff_creator is initialized with this _outbuff_creator, and whose _fpack is initialized with pack(this->_fpack, std::forward<FPE>(fpe)...)

template <typename... FPE>
/* see below */ with(FPE&&...) &&;
Compile-time requirements
Return Type
destination_no_reserve< OutbuffCreator
                      , decltype(pack( std::declval<const FPack&>()
                                     , std::forward<FPE>(fpe)...) ) >
Effect

Creates an destination_no_reserve object whose _outbuff_creator is initialized with std::move(_outbuff_creator), and whose _fpack is initialized with pack(std::move(this->_fpack), std::forward<FPE>(fpe)...)

Size reserve
constexpr destination_calc_size<OutbuffCreator, FPack> reserve_calc() const &;
Compile-time requirements
Effect

Creates an destination_calc_size object whose _outbuff_creator is initialized with this _outbuff_creator, and whose _fpack is initialized with this _fpack.

constexpr destination_calc_size<OutbuffCreator, FPack> reserve_calc() &&;
Compile-time requirements
Effect

Creates an destination_calc_size object whose _outbuff_creator is initialized with std::move(_outbuff_creator) from this object, and whose _fpack object is initialized with std::move(_fpack) from this object.

constexpr destination_with_given_size<OutbuffCreator, FPack>
reserve(std::size_t size) const &;
Compile-time requirements
Effect

Creates an destination_with_given_size whose _size is initialized with size, whose _outbuff_creator is initialized with this _outbuff_creator, and whose _fpack is initialized with this _fpack.

constexpr destination_with_given_size<OutbuffCreator, FPack>
reserve(std::size_t size) &&;
Compile-time requirements

OutbuffCreator is MoveConstructible and SizedOutbuffCreator.

Effect

Creates an destination_with_given_size object whose _size is initialized with size, whose _outbuff_creator is initialized with std::move(_outbuff_creator) from this object, and whose `_fpack is initialized with std::move(_fpack) from this object.

constexpr destination_no_reserve&  no_reserve() &;
constexpr destination_no_reserve&& no_reserve() &&;
constexpr const destination_no_reserve&  no_reserve() const &;
constexpr const destination_no_reserve&& no_reserve() const &&;
Effect

None.

Return

This object.

Printing
template <typename... Args>
/*...*/ operator()(const Args&... args) const;
Compile-time requirements
Effect
  1. Creates the outbuff object doing

    typename OutbuffCreator::outbuff_type ob{_outbuff_creator.create()};
  2. For each arg in args..., does

    using preview_type = print_preview<preview_size::no, preview_width::no>;
    preview_type preview;
    using printer_type = printer_type<char_type, preview_type, FPack, Arg>;
    printer_type p{ make_printer_input<char_type>(preview, _fpack, arg) };
    static_cast<const printer<char_type>&>(p).print_to(ob);

    where Arg is the type in Args... corresponding to arg

  3. Returns ob.finish() if such expression is valid, which is optional. Otherwise the return type is void.

template <typename …​ Args>
/*...*/ tr( const char_type* tr_string
          , const Args&... args) const;

template <typename …​ Args>
/*...*/ tr( const std::basic_string_view<char_type>& tr_string
          , const Args&... args) const;

template <typename …​ Args>
/*...*/ tr( std::basic_string_view<char_type> tr_string
          , const Args&... args) const;
Compile-time requirements
Effect

to-do

5.2. Class template destination_calc_size

template <typename SizedOutbuffCreator, typename FPack = facets_pack<>>
class destination_calc_size;
Compile-time requirements

Synopsis

namespace strf {

template <typename SizedOutbuffCreator, typename FPack>
class destination_reserve_calc
{
public:
    using char_type = typename SizedOutbuffCreator::char_type;

    // constructors
    template <typename... Args>
    constexpr destination_reserve_calc(Args&&...);

    constexpr destination_reserve_calc(const destination_reserve_calc&) = default;
    constexpr destination_reserve_calc(destination_reserve_calc&&) = default;

    // facets
    template <typename... FPE>
    destination_reserve_calc<SizedOutbuffCreator, /*...*/> with(FPE&&...) const &;

    template <typename... FPE>
    destination_reserve_calc<SizedOutbuffCreator, /*...*/> with(FPE&&...) &&;

    // size reserve
    constexpr destination_no_reserve<SizedOutbuffCreator, FPack>
    no_reserve() const &;

    constexpr destination_no_reserve<SizedOutbuffCreator, FPack>
    no_reserve() &&;

    constexpr destination_with_given_size<SizedOutbuffCreator, FPack>
    reserve(std::size_t) const &;

    constexpr destination_with_given_size<SizedOutbuffCreator, FPack>
    reserve(std::size_t) &&;

    constexpr destination_reserve_calc&  reserve_calc() &;
    constexpr destination_reserve_calc&& reserve_calc() &&;
    constexpr const destination_reserve_calc&  reserve_calc() const &;
    constexpr const destination_reserve_calc&& reserve_calc() const &&;

    // printing
    template <typename... Args>
    /*...*/ operator()(const Args&...) const;

    template <typename... Args>
    /*...*/ tr(const char_type*, const Args&...) const;

    template <typename... Args>
    /*...*/ tr(const std::basic_string<char_type>&, const Args&...) const;

    template <typename... Args>
    /*...*/ tr(std::basic_string_view<char_type>, const Args&...) const;

private:
    OutbuffCreator _outbuff_creator; // exposition only
    FPack _fpack;                    // exposition only
};

} // namespace strf
Constructors
template <typename... Args>
constexpr destination_reserve_calc(Args&&... args);
Compile-time requirements
  • FPack is DefaultConstructible

  • std::is_constructible<OutbuffCreator, Args...>::value is true, otherwise this constructor does not participate on overload resolution.

Effect
  • Initializes _outbuff_creator with std::forward<Args>(args)....

constexpr destination_reserve_calc(const destination_reserve_calc&) = default;

Copy constructor.

Compile-time requirements
constexpr destination_reserve_calc(destination_reserve_calc&&) = default;

Move constructor.

Facets
template <typename... FPE>
/* see below */ with(FPE&&...) const &;
Compile-time requirements
Return Type
destination_reserve_calc< OutbuffCreator
                        , decltype(pack( std::declval<const FPack&>()
                                       , std::forward<FPE>(fpe)...) ) >
Effect

Creates an destination_reserve_calc object whose _outbuff_creator is initialized with this _outbuff_creator, and whose _fpack is initialized with pack(this->_fpack, std::forward<FPE>(fpe)...)

template <typename... FPE>
/* see below */ with(FPE&&...) &&;
Compile-time requirements
Return Type
destination_reserve_calc< OutbuffCreator
                        , decltype(pack( std::declval<const FPack&>()
                                       , std::forward<FPE>(fpe)...) ) >
Effect

Creates an destination_reserve_calc object whose _outbuff_creator is initialized with std::move(this->_outbuff_creator), and whose _fpack is initialized with pack(std::move(this->_fpack), std::forward<FPE>(fpe)...)

Size reserve
constexpr destination_no_reserve<OutbuffCreator, FPack> no_reserve() const &;
Compile-time requirements
Effect

Creates an destination_no_reserve object whose _outbuff_creator is initialized with this _outbuff_creator, and whose _fpack is initialized with this _fpack.

constexpr destination_calc_size<OutbuffCreator, FPack> reserve_calc() &&;
Compile-time requirements
Effect

Creates an destination_no_reserve object whose _outbuff_creator is initialized with std::move(_outbuff_creator) from this object, and whose _fpack object is initialized with std::move(_fpack) from this object.

constexpr destination_with_given_size<OutbuffCreator, FPack>
reserve(std::size_t size) const &;
Compile-time requirements
Effect

Creates an destination_with_given_size whose _size is initialized with size, whose _outbuff_creator is initialized with this _outbuff_creator, and whose _fpack is initialized with this _fpack.

constexpr destination_with_given_size<OutbuffCreator, FPack>
reserve(std::size_t) &&;
Compile-time requirements

OutbuffCreator is MoveConstructible and SizedOutbuffCreator.

Effect

Creates an destination_with_given_size object whose _size is initialized with size, whose _outbuff_creator is initialized with std::move(_outbuff_creator) from this object, and whose `_fpack is initialized with std::move(_fpack) from this object.

constexpr destination_reserve_calc&  reserve_calc() &;
constexpr destination_reserve_calc&& reserve_calc() &&;
constexpr const destination_reserve_calc&  reserve_calc() const &;
constexpr const destination_reserve_calc&& reserve_calc() const &&;
Effect

None.

Return

This object.

Printing
template <typename... Args>
/*...*/ operator()(const Args&... args) const;
Compile-time requirements
Effect
  1. Creates an object preview of type print_preview<preview_size::yes, preview_width::no>.

    using preview_type = print_preview<preview_size::yes, preview_width::no>;
    preview_type preview;
  2. For each arg in args..., creates a printer object by doing:

    using printer_type = printer_type<char_type, preview_type, FPack, Arg>;
    printer_type p{ make_printer_input<char_type>(preview, _fpack, arg) };
  3. Creates/get the outbuff object doing

    using ob_type = typename OutbuffCreator::size_outbuf_type;
    ob_type ob{_outbuff_creator.create(preview.get_size())};
  4. For each p object does:

    static_cast<const printer<char_type>&>(p).print_to(ob);
  5. Returns ob.finish() if such expression is valid, which is optional. Otherwise the return type is void.

template <typename …​ Args>
/*...*/ tr( const char_type* tr_string
          , const Args&... args) const;

template <typename …​ Args>
/*...*/ tr( const std::basic_string_view<char_type>& tr_string
          , const Args&... args) const;

template <typename …​ Args>
/*...*/ tr( std::basic_string_view<char_type> tr_string
          , const Args&... args) const;
Compile-time requirements
Effect

to-do

5.3. Class template destination_with_given_size

template <typename SizedOutbuffCreator, typename FPack = facets_pack<>>
class destination_with_given_size
Compile-time requirements

Synopsis

namespace strf {

template <typename SizedOutbuffCreator, typename FPack>
class destination_with_given_size
{
public:
    using char_type = typename SizedOutbuffCreator::char_type;

    // constructors
    template <typename... Args>
    constexpr destination_with_given_size(std::size_t, Args&&...);
    constexpr destination_with_given_size(const destination_with_given_size&) = default;
    constexpr destination_with_given_size(destination_with_given_size&&) = default;

    // facets
    template <typename... FPE>
    destination_with_given_size<SizedOutbuffCreator, /*...*/> with(FPE&&...) const &;

    template <typename... FPE>
    destination_with_given_size<SizedOutbuffCreator, /*...*/> with(FPE&&...) &&;

    // size reserve
    constexpr destination_calc_size<SizedOutbuffCreator, FPack>
    reserve_calc() const &;

    constexpr destination_calc_size<SizedOutbuffCreator, FPack>
    reserve_calc() &&;

    constexpr destination_no_reserve<SizedOutbuffCreator, FPack>
    no_reserve() const &;

    constexpr destination_no_reserve<SizedOutbuffCreator, FPack>
    no_reserve() &&;

    constexpr destination_with_given_size&  reserve(std::size_t) &;
    constexpr destination_with_given_size&& reserve(std::size_t) &&;
    constexpr destination_with_given_size   reserve(std::size_t) const &;
    constexpr destination_with_given_size   reserve(std::size_t) const &&;

    // printing
    template <typename... Args>
    /*...*/ operator()(const Args&...) const;

    template <typename... Args>
    /*...*/ tr(const char_type*, const Args&...) const;

    template <typename... Args>
    /*...*/ tr(const std::basic_string<char_type>&, const Args&...) const;

    template <typename... Args>
    /*...*/ tr(std::basic_string_view<char_type>, const Args&...) const;

private:
    std::size_t _size              // exposition only
    OutbuffCreator _outbuff_creator; // exposition only
    FPack _fpack;                  // exposition only
};

} // namespace strf
Constructors
template <typename... Args>
constexpr destination_with_given_size(std::size_t size, Args&&... args);
Compile-time requirements
  • FPack is DefaultConstructible

  • std::is_constructible<OutbuffCreator, Args...>, otherwise this constructor does not participate on overload resolution.

Effect
  • Initializes _outbuff_creator with std::forward<Args>(args)....

  • Initializes _size with size

constexpr destination_with_given_size(const destination_with_given_size&) = default;

Copy constructor.

Compile-time requirements
constexpr destination_with_given_size(destination_with_given_size&&) = default;

Move constructor.

Facets
template <typename... FPE>
/* see below */ with(FPE&&...) const &;
Compile-time requirements
Return Type
destination_with_given_size< OutbuffCreator
                           , decltype(pack( std::declval<const FPack&>()
                                          , std::forward<FPE>(fpe)...) ) >
Effect

Creates an destination_with_given_size object whose _size is is initialized with this _size , whose _outbuff_creator is initialized with this _outbuff_creator , and whose _fpack is initialized with pack(this->_fpack, std::forward<FPE>(fpe)...)

template <typename... FPE>
/* see below */ with(FPE&&...) &&;
Compile-time requirements
Return Type
destination_with_given_size< OutbuffCreator
                           , decltype(pack( std::declval<const FPack&>()
                                          , std::forward<FPE>(fpe)...) ) >
Effect

Creates an destination_with_given_size object whose _size is is initialized with this _size , whose _outbuff_creator is initialized with std::move(_outbuff_creator) from this object , and whose _fpack is initialized with pack(std::move(this->_fpack), std::forward<FPE>(fpe)...)

Size reserve
constexpr destination_no_reserve<OutbuffCreator, FPack> no_reserve() const &;
Compile-time requirements
Effect

Creates an destination_no_reserve object whose _outbuff_creator is initialized with this _outbuff_creator, and whose _fpack is initialized with this _fpack.

constexpr destination_calc_size<OutbuffCreator, FPack> no_reserve() &&;
Compile-time requirements
Effect

Creates an destination_no_reserve object whose _outbuff_creator is initialized with std::move(_outbuff_creator) from this object, and whose _fpack object is initialized with std::move(_fpack) from this object.

constexpr destination_calc_size<OutbuffCreator, FPack> reserve_calc() const &;
Compile-time requirements
Effect

Creates an destination_calc_size object whose _outbuff_creator is initialized with this _outbuff_creator, and whose _fpack is initialized with this _fpack.

constexpr destination_calc_size<OutbuffCreator, FPack> reserve_calc() &&;
Compile-time requirements
Effect

Creates an destination_calc_size object whose _outbuff_creator is initialized with std::move(_outbuff_creator) from this object, and whose _fpack object is initialized with std::move(_fpack) from this object.

constexpr destination_with_given_size&  reserve(std::size_t size) &;
constexpr destination_with_given_size&& reserve(std::size_t size) &&;
Effect

assign size to _size.

Return

This object.

constexpr destination_with_given_size reserve(std::size_t size) const &;
constexpr destination_with_given_size reserve(std::size_t size) const &&;
Effect

Creates an destination_with_give_size object whose _size is initialized with size, whose _outbuff_creator is initialized with this _outbuff_creator, and whose facets_pack object with this _fpack.

Printing
template <typename... Args>
/*...*/ operator()(const Args&... args) const;
Compile-time requirements
Effect
  1. Creates/get the outbuff object doing

    decltype(auto) ob = _outbuff_creator.create(_size)
  2. For each arg in args... does:

    using preview_type = print_preview<preview_size::no, preview_width::no>;
    preview_type preview;
    using printer_type = printer_type<char_type, preview_type, FPack, Arg>;
    printer_type p{ make_printer_input<char_type>(preview, _fpack, arg) };
    static_cast<const printer<char_type>&>(p).print_to(ob);

    , where Arg is the type in Args... corresponding to arg

  3. Returns ob.finish() if such expression is valid, which is optional. Otherwise the return type is void.

template <typename …​ Args>
/*...*/ tr( const char_type* tr_string
          , const Args&... args) const;

template <typename …​ Args>
/*...*/ tr( const std::basic_string_view<char_type>& tr_string
          , const Args&... args) const;

template <typename …​ Args>
/*...*/ tr( std::basic_string_view<char_type> tr_string
          , const Args&... args) const;
Compile-time requirements
Effect

to-do

5.4. Type requirement OutbuffCreator

Given

  • char_type, a character type

  • X, an OutbuffCreator type for char_type

  • x, an expression of type X or const X

The following must hold:

  • X is CopyConstructible

  • X has a member type alias X::char_type defined as char_type

  • X has the X::outbuff_type that is a type alias to a concrete type that is derives from basic_outbuff<X::char_type>

And the following expression must be satisfied:

typename X::outbuff_type{x.create()}

5.5. Type requirement SizedOutbuffCreator

Given

  • char_type, a character type

  • size, a value of the std::size_t

  • X, an OutbuffCreator type for char_type

  • x, an expression of type X or const X

The following must hold:

  • X is CopyConstructible

  • X has a member type alias T::char_type defined as char_type

  • X has the X::size_outbuff_type that is a type alias to a concrete type that is derives from basic_outbuff<X::char_type>

And the following expression must be satisfied:

typename X::sized_outbuff_type{x.create(size)}
Return type

A type that derives from basic_outbuff<char_type>

Postcondition

ob.size() >= size, where ob is the returned value.

6. Tr-String

6.1. Syntax

A '{' followed by until means

'-'

the next '}' or end of string

a comment

a digit

the next '}' or end of string

a positional argument reference

another '{'

the second '{'

an escaped '{'

any other character

the next '}' or end of string

a non positional argument reference

Examples:

Comments
auto str = strf::to_string.tr
    ( "You can learn more about python{-the programming language, not the reptile} at {}"
    , "www.python.org" );
assert(str == "You can learn more about python at www.python.org");
Positional arguments
auto str = strf::to_string.tr("{1 a person} likes {0 a food type}.", "sandwich", "Paul");
assert(str == "Paul likes sandwich.");
Non positional arguments
auto str = strf::to_string.tr("{a person} likes {a food type}.", "Paul", "sandwich");
assert(str == "Paul likes sandwich.");
Escapes
auto str = strf::to_string.tr("} {{x} {{{} {{{}}", "aaa", "bbb");
assert(str == "} {x} {aaa {bbb}");

Syntax error handling

When the argument associated with a "{" does not exists, the library does two things:

  • It prints a replacement character "\uFFFD" (�) ( or "?" when the encoding can’t represent it ) where the missing argument would be printed.

  • It calls the handle function on the facet object correspoding to the tr_error_notifier_c category.

6.2. Facet category tr_error_notifier_c

For a type to be a facet of the tr_error_notifier_c, it must satisfy the requirements of TrErrorHandling

namespace strf {

struct tr_error_notifier_c {
    static constexpr default_tr_error_notifier get_default() noexcept
    {
        return default_tr_error_notifier{};
    }
};

} // namespace strf

Struct default_tr_error_notifier

default_tr_error_notifier is the default facet of the tr_error_notifier_c category. It’s a dummy error handler.

namespace strf {

struct default_tr_error_notifier {
    using category = tr_error_notifier_c;

    template <typename CharEncoding>
    void handle
        ( const typename CharEncoding::char_type* str
        , std::size_t str_len
        , std::size_t err_pos
        , CharEncoding enc ) noexcept
    {
    }
};

} // namespace strf

Type requirement TrErrorHandling

Given:

  • X, a TrErrorHandling type

  • x, a value of type X

  • Enc, a CharEncoding type.

  • enc, a value of type Enc

  • str, a value of type const Enc::char_type* pointing to string encoded according to enc

  • str_len, a std::size_t value equal to the length of the string str

  • err_pos, a std::size_t value less than or equal to str_len

The following must host:

  • X is CopyConstructible.

  • X::category is a type alias to tr_error_notifier_c

  • The following expression is supported:

x.handle(str, str_len, err_pos, enc)
Semantics

str is a tr-string that contains an error. err_pos is the position of the '{' character in str that starts the invalid argument reference.

7. Character encodings

7.1. Enumeration char_encoding_id

namespace strf {
enum class char_encoding_id : unsigned { };

constexpr char_encoding_id  eid_ascii        = /* ... */;
constexpr char_encoding_id  eid_utf8         = /* ... */;
constexpr char_encoding_id  eid_utf16        = /* ... */;
constexpr char_encoding_id  eid_utf32        = /* ... */;
constexpr char_encoding_id  eid_iso_8859_1   = /* ... */;
constexpr char_encoding_id  eid_iso_8859_3   = /* ... */;
constexpr char_encoding_id  eid_iso_8859_15  = /* ... */;
constexpr char_encoding_id  eid_windows_1252 = /* ... */;

} // namespace strf

7.2. Facet category invalid_seq_notifier_c

namespace strf {
struct invalid_seq_notifier_c {
    static constexpr bool constrainable = false;
    static constexpr invalid_seq_notifier get_default() noexcept {
        return {}
    }
};
} // namespace strf

Class invalid_seq_notifier

namespace strf {

class invalid_seq_notifier {
public:

    using category = invalid_seq_notifier_c;

    typedef void(*notify_fptr)();

    constexpr invalid_seq_notifier() noexcept = default;
    constexpr invalid_seq_notifier(const invalid_seq_notifier&) noexcept = default;

    constexpr explicit invalid_seq_notifier(notify_fptr) noexcept;
    constexpr invalid_seq_notifier& operator=(notify_fptr) noexcept;
    constexpr invalid_seq_notifier& operator=(const invalid_seq_notifier& other) noexcept;
    constexpr bool operator==(const invalid_seq_notifier& other) noexcept;
    constexpr operator bool() const noexcept;
    constexpr void notify() const noexcept;

private:
    notify_fptr notify_func_ = nullptr; // exposition only
};

} // namespace strf
constexpr invalid_seq_notifier() noexcept;

Trivial default constructor

Poscondition

notify_func_ == nullptr

constexpr invalid_seq_notifier(const invalid_seq_notifier& other) noexcept;

Trivial copy constructor

Poscondition

notify_func_ == other.notify_func_

constexpr explicit invalid_seq_notifier(notify_fptr fptr) noexcept;
Poscondition

notify_func_ == fptr

constexpr invalid_seq_notifier& operator=(const invalid_seq_notifier& other) noexcept;
Poscondition

notify_func_ == other.notify_func_

constexpr bool operator==(const invalid_seq_notifier& other) noexcept;
Return value

notify_func_ == other.notify_func_

constexpr operator bool() const noexcept;
Return value

notify_func_ != nullptr

constexpr void notify() const noexcept;
Effect

Calls notify_func_ if it is not null.

7.3. Facet category surrogate_policy_c

enum class surrogate_policy : bool { strict = false, lax = true };

struct surrogate_policy_c {
    static constexpr bool constrainable = false;
    static constexpr surrogate_policy get_default() noexcept {
        return surrogate_policy::strict;
    }
};

template <>
class facet_traits<surrogate_policy> {
public:
    using category = surrogate_policy_c;
    static constexpr bool store_by_value = true;
};

Semantics

This facet enables you to choose whether a nonconformant presence of a surrogate character shall be treated as invalid.

7.4. Facet category template char_encoding_c

namespace strf {

template <typename CharT>
struct char_encoding_c {
    static constexpr bool constrainable = false;
    static constexpr utf<CharT> get_default() noexcept;
};

template <typename CharT, char_encoding_id CEId>
struct facet_traits<static_char_encoding<CharT, CEId>>
{
    using category = char_encoding_c<CharT>;
};

template <typename CharT>
struct facet_traits<dynamic_char_encoding<CharT>>
{
    using category = char_encoding_c<CharT>;
};
} // namespace strf

For a type to be a facet of char_encoding_c<CharT> it has to be a CharEncoding type for CharT. The library provides two class templates that satisfy that: static_char_encoding and dynamic_char_encoding

7.5. Aliases for pointers to functions

constexpr std::size_t invalid_char_len = (std::size_t)-1;

template <typename SrcCharT, typename DestCharT>
using transcode_f = void (*)
    ( basic_outbuff<DestCharT>& ob
    , const SrcCharT* src
    , std::size_t src_size
    , invalid_seq_notifier inv_seq_notifier
    , surrogate_policy surr_poli );

template <typename SrcCharT>
using transcode_size_f = std::size_t (*)
    ( const SrcCharT* src
    , std::size_t src_size
    , surrogate_policy surr_poli );

template <typename CharT>
using write_replacement_char_f = void(*)( basic_outbuff<CharT>& );

using validate_f = std::size_t (*)(char32_t ch);

using encoded_char_size_f = std::size_t (*) (char32_t ch);

template <typename CharT>
using encode_char_f = CharT*(*) (CharT* dest, char32_t ch);

template <typename CharT>
using encode_fill_f = void (*)
    ( basic_outbuff<CharT>&
    , std::size_t count
    , char32_t ch );

struct codepoints_count_result {
    std::size_t count;
    std::size_t pos;
};

template <typename CharT>
using codepoints_fast_count_f = codepoints_count_result (*)
    ( const CharT* src
    , std::size_t src_size
    , std::size_t max_count );

template <typename CharT>
using codepoints_robust_count_f = codepoints_count_result (*)
    ( const CharT* src
    , std::size_t src_size
    , std::size_t max_count
    , surrogate_policy surr_poli );

template <typename CharT>
using decode_char_f = char32_t (*) ( CharT );

template <typename SrcCharT, typename DestCharT>
using find_transcoder_f = dynamic_transcoder<SrcCharT, DestCharT> (*)
    ( char_encoding_id );

7.6. Type requirement Transcoder

Given

  • SrcCharT, one of the types: char, char8_t, char16_t, char32_t or wchar_t

  • DestCharT, one of the types: char, char8_t, char16_t, char32_t or wchar_t

  • X, a Transcoder type from SrcCharT to DestCharT

  • x, an expression of type X or const X

  • dest, an lvalue reference of type basic_outbuff<DestCharT>

  • src, a value of type const SrcCharT*

  • src_size, a value of type std::size_t equal to the size of the array pointed by src

  • inv_seq_notifier, a value of type invalid_seq_notifier

  • surr_poli, a value of type surrogate_policy

The following must hold:

x.transcode_size(src, src_size, surr_poli)
Return type

std::size_t

Return value

The number of character that x.transcode(dest, src, src_size, invalid_seq_notifier{}, surr_poli) would write into dest, or a value a greater than that if such exact calculation is difficult ( but ideally not much greater ).

Precondition

x.transcode_func() != nullptr is true

x.transcode(dest, src, src_size, inv_seq_notifier, surr_poli)
Effect

Converts the content of src from one encoding to another writing the result to dest. Each sequence in src that is invalid is translated instead by the replacement character ( that is returned by x.replacement_char(). And each time that happens, inv_seq_notifier.notify() shall be called if the value of (bool)inv_seq_notifier is true. A sequence in src is considered invalid if is non-conformant to its corresponding encoding or would cause content written in dest to be non-conformant to the destination encoding, unless such non-conformity is due to a surrogate character and the value of surr_poli is surrogate_policy::lax.

Precondition

x.transcode_func() != nullptr is true

Postconditions

dest.recycle() is not called() if dest.size() >= x.transcode_size(src, src_size, surr_poli) is true.

x.transcode_size_func()
Return type

transcode_size_f<SrcCharT>

Return value

A function pointer such that x.transcode_size_func() (src, src_size, surr_poli) has the same effect as x.transcode_size(src, src_size, surr_poli).

x.transcode_func()
Return type

transcode_f<SrcCharT, DestCharT>

Return value

A function pointer such that x.transcode_func() (dest, src, src_size, inv_seq_notifier, surr_poli) has the same effect as x.transcode(dest, src, src_size, inv_seq_notifier, surr_poli).


Definition

A null transcoder is an object of an Transcoder type where the transcode_func function returns nullptr.

There are two class templates that satisfy Transcoder: static_transcoder and dynamic_transcoder.

7.7. Type requirement CharEncoding

Given

  • CharT, one of the follwoing types: char, char8_t, char16_t, char32_t or wchar_t

  • X, a CharEncoding type for type CharT

  • x, an expression of type X or const X

  • OtherCharT, one of the folowing types : char, char8_t, char16_t or wchar_t

  • ptr, a value of type CharT*

  • src, a value of type const CharT*

  • src_size, a value of type std::size_t equal to the size of the array pointed by src

  • count, a value of type std::size_t

  • max_count, a value of type std::size_t

  • ch32, a value of type char32_t

  • ch, a value of type CharT

  • ob, an lvalue reference of type basic_outbuff<CharT>

  • enc_id, value of type char_encoding_id

The following must hold:

X::char_type

Type alias to CharT

x.id()
Return type

char_encoding_id

Return value

The char_encoding_id that corresponds to this encoding.

x.name()
Return type

const char*

Return value

The name of this encoding. Examples: "UTF-8", "ASCII", "ISO-8859-1", "windows-1252".

x.replacement_char()
Return type

char32_t

Return value

The character used to signalize an error. Usually it is the replacement character � if it is supported by this encoding, or the question mark '?' otherwise.

x.write_replacement_char(ob)
Return type

Writes into ob the codepoint returned by x.replacement_char() encoded in this encoding.

x.replacement_char_size()
Return type

std::size_t

Return value

The number of characters that x.write_replacement_char(ob) writes into ob.

x.encoded_char_size(ch32)
Return type

std::size_t

Return value

The size of the string containing the UTF-32 character ch32, if ch32 is supported in this encoding. Otherwise, same as x.replacement_char_size() otherwise.

Note

This function does not check whether ch32 is a legal code point, only if it is possible to write it in this encoding. For example, if this is encoding is UTF-32, this function considers as valid any value for ch32 ( even if is is greater than 0x10FFFF ). Surrogates characters are also not sanitized.

x.validate(ch32)
Return type

std::size_t

Return value

The size of the string containing the UTF-32 character ch32, if ch32 is supported in this encoding. Otherwise, (std::size_t)-1.

x.encode_char(ptr, ch32)
Effect

Writes into ptr the UTF-32 character ch32 encoded into this encoding, adopting the policy of surrogate_policy::lax, i.e. if ch32 is a surrogate, treat it as if it were a valid codepoint. If this encoding is not able to encode ch32, then encode instead the return of x.replacement_char().

Return type

CharT*

Return value

The position just after the last writen character.

Note

This function does not check whether ch32 is a legal code point, only if it is possible to write it in this encoding. For example, if this is encoding is UTF-32, this function considers as valid any value for ch32 ( even if is is greater than 0x10FFFF ). Surrogates characters are also not sanitized.

x.encode_fill(ob, count, ch32)
Effect

Writes count times into ob the UTF-32 character ch32 encoded into this encoding, if it is supported. Otherwise writes x.replacement_char() instead.

Return type

void

Note

encode_fill does not check whether ch32 is a legal code point, only if it is possible to write it in this encoding. For example, if this is encoding is UTF-32, encode_fill considers as valid any value for ch32 ( even if is is greater than 0x10FFFF ). Surrogates characters are also not sanitized.

x.codepoints_fast_count(src, src_size, max_count)
Return type

codepoints_count_result

Return value

{c, pos}, where:

  • c is the number of Unicode code points in src, if such value is less than max_count. Otherwise, c is equal to max_count.

  • pos is such that the number of codepoints in src is equal to c.

Posconditions
  • c <= max_count is true

  • pos <= src_size is true

Note

If the input is non-conformant to the corresponding character encoding, this function may return an incorrect value. For instance, for UTF-8 this function may simply count the bytes that are not continuation bytes.

x.codepoints_robust_count(src, src_size, max_count, surr_poli)
Effect

Counts the codepoints until is equal to max_count.

Return type

codepoints_count_result

Return value

{c, pos}, where:

  • c is equal to std::min(max_count, u32len), where u32len is the length of the UTF-32 string that would be generated by converting src from this encoding to UTF-32, according to surr_poli.

  • pos is such that the value of x.codepoints_robust_count(src, pos, (std::size_t)-1, surr_poli).count is equal to c.

Posconditions
  • c <= max_count is true

  • pos <= src_size is true

x.decode_char(ch)
Effect

Decodes ch from this encoding to UTF-32 assuming the policy of surrogate_policy::lax. If ch is an invalid character, return x.replacement_char().

Return type

char32_t

x.encode_char_func()
Return type

encode_char_f<CharT>

Return value

A function pointer such that x.encode_char_func() (ch32) has the same effect as x.encode_char(ch32).

x.encode_fill_func()
Return type

encode_fill_f<CharT>

Return value

A function pointer such that x.encode_fill_func() (ob, count, ch32) has the same effect as x.encode_fill(ob, count, ch32).

x.write_replacement_char_func()
Return type

write_replacement_char_f<CharT>

Return value

A function pointer such that x.write_replacement_char_func() (ob) has the same effect as x.write_replacement_char(ob)

x.from_u32()
Return type

A Transcoder from char32_t to CharT

Return value

A transcoder that converts UTF-32 to this encoding.

x.to_u32()
Return type

A Transcoder from CharT to char32_t

Return value

A transcoder that converts this encoding to UTF-32.

x.sanitizer()
Return type

A Transcoder from CharT to CharT

Return value

A transcoder that "converts" this encoding to this encoding, i.e. a sanitizer of this encoding.

( Optional )
x.find_transcoder_to(tag<OtherCharT>, enc_id)
Return type

dynamic_transcoder<CharT, OtherCharT>

Return value

A transcoder that converts this encoding to the encoding corresponding to enc_id, or an null transcoder.

( Optional )
x.find_transcoder_from(tag<OtherCharT>, enc_id)
Return type

dynamic_transcoder<OtherCharT, CharT>

Return value

A transcoder that converts the encoding corresponding to enc_id to this encoding, or an null transcoder.

You shall not create an CharEncoding for char32_t, since char32_t is reserved for UTF-32. The library internaly assumes in many occasions that the encoding is UTF-32 when CharT is char32_t.
There are two class templates that satisfy CharEncoding: static_transcoder and dynamic_char_encoding.

7.8. Class template static_transcoder

template <char_encoding_id Src, char_encoding_id Dest>
class static_transcoder;

template <> static_transcoder<eid_ascii, eid_ascii>;
template <> static_transcoder<eid_ascii, eid_utf32>;
template <> static_transcoder<eid_utf32, eid_ascii>;
template <> static_transcoder<eid_iso_8859_1, eid_iso_8859_1>;
template <> static_transcoder<eid_iso_8859_1, eid_utf32>;
template <> static_transcoder<eid_utf32, eid_iso_8859_1>;
template <> static_transcoder<eid_iso_8859_3, eid_utf32>;
template <> static_transcoder<eid_utf32, eid_iso_8859_3>;
template <> static_transcoder<eid_iso_8859_3, eid_iso_8859_3>;
template <> static_transcoder<eid_iso_8859_15, eid_iso_8859_15>;
template <> static_transcoder<eid_iso_8859_15, eid_utf32>;
template <> static_transcoder<eid_utf32, eid_iso_8859_15>;
template <> static_transcoder<eid_windows_1252, eid_windows_1252>;
template <> static_transcoder<eid_windows_1252, eid_utf32>;
template <> static_transcoder<eid_utf32, eid_windows_1252>;
template <> static_transcoder<eid_utf8, eid_utf8>;
template <> static_transcoder<eid_utf8, eid_utf16>;
template <> static_transcoder<eid_utf8, eid_utf32>;
template <> static_transcoder<eid_utf16, eid_utf8>;
template <> static_transcoder<eid_utf16, eid_utf16>;
template <> static_transcoder<eid_utf16, eid_utf32>;
template <> static_transcoder<eid_utf32, eid_utf8>;
template <> static_transcoder<eid_utf32, eid_utf16>;
template <> static_transcoder<eid_utf32, eid_utf32>;

static_transcoder class template has no generic implementation. Instead, the library provides the template specializations listed above. All of them are empty classes, and are Transcoder, and their member functions transcode_func and transcode_size_func never return nullptr.

7.9. Class template static_char_encoding

template <char_encoding_id>
class static_char_encoding;

template <> class static_char_encoding<eid_utf8>;
template <> class static_char_encoding<eid_utf16>;
template <> class static_char_encoding<eid_utf32>;
template <> class static_char_encoding<eid_ascii>;
template <> class static_char_encoding<eid_iso_8859_1>;
template <> class static_char_encoding<eid_iso_8859_3>;
template <> class static_char_encoding<eid_iso_8859_15>;
template <> class static_char_encoding<eid_windows_1252>;

static_char_encoding class template has no generic implementation. Instead, the library provides the template specializations listed above. All of them are empty classes, and are CharEncoding.

7.10. Class template dynamic_transcoder

namespace strf {

template <typename SrcCharT, typename DestCharT>
class dynamic_transcoder {
public:
    constexpr dynamic_transcoder() noexcept;

    constexpr dynamic_transcoder
        ( const dynamic_transcoder& other) noexcept = default;

    template <char_encoding_id Src, char_encoding_id Dest>
    constexpr explicit dynamic_transcoder
        ( static_transcoder<Src, Dest> st );

    void transcode
        ( basic_outbuff<DestCharT>& ob
        , const SrcCharT* src
        , std::size_t src_size
        , invalid_seq_notifier inv_seq_notifier
        , surrogate_policy surr_poli ) const;

    std::size_t transcode_size
        ( const SrcCharT* src
        , std::size_t src_size
        , surrogate_policy surr_poli ) const;

    constexpr transcode_f<SrcCharT, DestCharT> transcode_func() const noexcept;
    constexpr transcode_size_f<SrcCharT> transcode_size_func() const noexcept;
};

} // namespace strf
constexpr dynamic_transcoder() noexcept;

Default constructor

Postconditions
  • transcode_func() == nullptr

  • transcode_size_func() == nullptr

constexpr dynamic_transcoder
    ( const dynamic_transcoder& other) noexcept;

Trivial copy constructor

Postconditions
  • transcode_func() == other.transcode_func()

  • transcode_size_func() == other.transcode_size_func()

template <char_encoding_id Src, char_encoding_id Dest>
constexpr explicit dynamic_transcoder
    ( static_transcoder<Src, Dest> other );
Postconditions
  • transcode_func() == other.transcode_func()

  • transcode_size_func() == other.transcode_size_func()

void transcode
    ( basic_outbuff<DestCharT>& ob
    , const SrcCharT* src
    , std::size_t src_size
    , invalid_seq_notifier inv_seq_notifier
    , surrogate_policy surr_poli ) const;

Effect: Calls transcode_func()(ob, src, src_size, inv_seq_notifier, surr_poli)

std::size_t transcode_size
    ( const SrcCharT* src
    , std::size_t src_size
    , surrogate_policy surr_poli ) const;

Effect: Calls transcode_size_func()(src, src_size, surr_poli)

7.11. Struct template dynamic_char_encoding_data

template <typename CharT>
struct dynamic_char_encoding_data {
    const char* name;
    char_encoding_id id;
    char32_t replacement_char;
    std::size_t replacement_char_size;
    validate_f validate_func;
    encoded_char_size_f encoded_char_size_func;
    encode_char_f<CharT> encode_char_func;
    encode_fill_f<CharT> encode_fill_func;
    codepoints_fast_count_f<CharT> codepoints_fast_count_func;
    codepoints_robust_count_f<CharT> codepoints_robust_count_func;

    write_replacement_char_f<CharT> write_replacement_char_func;
    decode_char_f<CharT> decode_char_func;

    dynamic_transcoder<CharT, CharT> sanitizer;
    dynamic_transcoder<char32_t, CharT> from_u32;
    dynamic_transcoder<CharT, char32_t> to_u32;

    find_transcoder_f<wchar_t, CharT> find_transcoder_from_wchar;
    find_transcoder_f<CharT, wchar_t> find_transcoder_to_wchar;

    find_transcoder_f<char16_t, CharT> find_transcoder_from_char16;;
    find_transcoder_f<CharT, char16_t> find_transcoder_to_char16;

    find_transcoder_f<char, CharT> find_transcoder_from_char;
    find_transcoder_f<CharT, char> find_transcoder_to_char;

#if defined (__cpp_char8_t)
    find_transcoder_f<char8_t, CharT> find_transcoder_from_char8;
    find_transcoder_f<CharT, char8_t> find_transcoder_to_char8;
#else
    void* find_transcoder_from_char8 = nullptr;
    void* find_transcoder_to_char8 = nullptr;
#endif

};

7.12. Class template dynamic_char_encoding

template <typename CharT>
class dynamic_char_encoding {
public:

    using char_type = CharT;

    dynamic_char_encoding(const dynamic_char_encoding& other) = default;

    dynamic_char_encoding
        ( const dynamic_char_encoding_data<CharT>& d );

    dynamic_char_encoding& operator=(const dynamic_char_encoding& other) noexcept;

    bool operator==(const dynamic_char_encoding& other) const noexcept;

    bool operator!=(const dynamic_char_encoding& other) const noexcept;

    void swap(dynamic_char_encoding& other) noexcept;

    const char* name() const noexcept;

    constexpr char_encoding_id id() const noexcept;

    constexpr char32_t replacement_char() const noexcept;

    constexpr std::size_t replacement_char_size() const noexcept;

    constexpr std::size_t validate(char32_t ch) const; // noexcept

    constexpr std::size_t encoded_char_size(char32_t ch) const; // noexcept

    char_type_* encode_char(char_type_* dest, char32_t ch) const; // noexcept

    void encode_fill
        ( basic_outbuff<CharT>& ob, std::size_t count, char32_t ch ) const;

    std::size_t codepoints_fast_count
        ( const char_type_* src, std::size_t src_size
        , std::size_t max_count ) const;

    std::size_t codepoints_robust_count
        ( const char_type_* src, std::size_t src_size
        , std::size_t max_count, surrogate_policy surr_poli ) const;

    void write_replacement_char(basic_outbuff<CharT>& ob) const;

    char32_t decode_char(char_type_ ch) const;

    encode_char_f<CharT> encode_char_func() const noexcept;

    encode_fill_f<CharT> encode_fill_func() const noexcept;

    write_replacement_char_f<CharT> write_replacement_char_func() const noexcept;

    dynamic_transcoder<char32_t, CharT> from_u32() const;

    dynamic_transcoder<CharT, char32_t> to_u32() const;

    dynamic_transcoder<CharT, CharT> sanitizer() const;

    dynamic_transcoder<CharT, wchar_t> find_transcoder_to
        ( tag<wchar_t>, char_encoding_id id) const;

    dynamic_transcoder<wchar_t, CharT> find_transcoder_from
        ( tag<wchar_t>, char_encoding_id id) const;

    dynamic_transcoder<CharT, char16_t> find_transcoder_to
        ( tag<char16_t>, char_encoding_id id) const;

    dynamic_transcoder<char16_t, CharT> find_transcoder_from
        ( tag<char16_t>, char_encoding_id id) const;

    dynamic_transcoder<CharT, char> find_transcoder_to
        ( tag<char>, char_encoding_id id) const;

    dynamic_transcoder<char, CharT> find_transcoder_from
        ( tag<char>, char_encoding_id id) const;

#if defined (__cpp_char8_t)
    dynamic_transcoder<CharT, char8_t> find_transcoder_to
        ( tag<char8_t>, char_encoding_id id) const;

    dynamic_transcoder<char8_t, CharT> find_transcoder_from
        ( tag<char8_t>, char_encoding_id id) const;
#endif

private:

    const dynamic_char_encoding_data* data; // exposition only
};
dynamic_char_encoding(const dynamic_char_encoding& other);

Trivial copy constructor.

Effect

this->data = other.data

dynamic_char_encoding
        ( const dynamic_char_encoding_data<CharT>& d );
Effect

this->data = d

dynamic_char_encoding& operator=(const dynamic_char_encoding& other) noexcept
Effect

this->data = other.data

bool operator==(const dynamic_char_encoding& other) const noexcept;
Return value

this->data == other.data

bool operator!=(const dynamic_char_encoding& other) const noexcept;
Return value

this->data != other.data

void swap(dynamic_char_encoding& other) noexcept;
Effect

Same as std::swap(this->data, other.data)

const char* name() const noexcept;
Return value

this->data->name

constexpr char_encoding_id id() const noexcept;
Return value

this->data->id

constexpr char32_t replacement_char() const noexcept;
Return value

this->data->replacement_char

constexpr std::size_t replacement_char_size() const noexcept;
Return value

this->data->replacement_char_size

constexpr std::size_t validate(char32_t ch) const; // noexcept
Effect

Calls and returns this->data->validate_func(ch).

constexpr std::size_t encoded_char_size(char32_t ch) const; // noexcept
Effect

Calls and returns this->data->encoded_char_size_func(ch).

char_type_* encode_char(char_type_* dest, char32_t ch) const; // noexcept
Effect

Calls and returns this->data->encoded_char_func(ch).

void encode_fill
    ( basic_outbuff<CharT>& ob, std::size_t count, char32_t ch ) const;
Effect

Calls and returns this->data->encode_fill_func(ob, count, ch).

std::size_t codepoints_fast_count
    ( const char_type_* src, std::size_t src_size
    , std::size_t max_count ) const;
Effect

Calls and returns this->data->codepoints_fast_count_func(src, src_size, max_count).

std::size_t codepoints_robust_count
    ( const char_type_* src, std::size_t src_size
    , std::size_t max_count, surrogate_policy surr_poli ) const;
Effect

Calls and returns this->data->codepoints_robust_count_func(src, src_size, max_count, surr_poli).

void write_replacement_char(basic_outbuff<CharT>& ob) const;
Effect

Calls this->data->write_replacement_char_func(ob).

char32_t decode_char(char_type_ ch) const;
Effect

Calls and returns this->data->decode_char_func(ch).

encode_char_f<CharT> encode_char_func() const noexcept;
encode_fill_f<CharT> encode_fill_func() const noexcept;
Return value

this->data->encode_fill_func.

write_replacement_char_f<CharT> write_replacement_char_func() const noexcept;
Return value

this->data->write_replacement_char_func.

dynamic_transcoder<char32_t, CharT> from_u32() const;
Return value

this->data->from_u32.

dynamic_transcoder<CharT, char32_t> to_u32() const;
Return value

this->data->to_u32.

dynamic_transcoder<CharT, CharT> sanitizer() const;
Return value

this->data->sanitizer.

dynamic_transcoder<CharT, char> find_transcoder_to
    ( tag<char>, char_encoding_id id) const;
Return value

this->data->transcoder_finder_to_char(id) if such function pointer is not null. Otherwise returns dynamic_transcoder<CharT, char>{}

dynamic_transcoder<char, CharT> find_transcoder_from
    ( tag<char>, char_encoding_id id) const;
Return value

this->data->transcoder_finder_from_char(id) if such function pointer is not null. Otherwise returns dynamic_transcoder<char, CharT>{}

dynamic_transcoder<CharT, char8_t> find_transcoder_to
    ( tag<char8_t>, char_encoding_id id) const;
Return value

this->data->transcoder_finder_to_char8(id) if such function pointer is not null. Otherwise returns dynamic_transcoder<CharT, char8_t>{}

dynamic_transcoder<char8_t, CharT> find_transcoder_from
    ( tag<char8_t>, char_encoding_id id) const;
Return value

this->data->transcoder_finder_from_char8(id) if such function pointer is not null. Otherwise returns dynamic_transcoder<char8_t, CharT>{}

dynamic_transcoder<CharT, char16_t> find_transcoder_to
    ( tag<char16_t>, char_encoding_id id) const;
Return value

this->data->transcoder_finder_to_char16(id) if such function pointer is not null. Otherwise returns dynamic_transcoder<CharT, char16_t>{}

dynamic_transcoder<char16_t, CharT> find_transcoder_from
    ( tag<char16_t>, char_encoding_id id) const;
Return value

this->data->transcoder_finder_from_char16(id) if such function pointer is not null. Otherwise returns dynamic_transcoder<char16_t, CharT>{}

dynamic_transcoder<CharT, wchar_t> find_transcoder_to
    ( tag<wchar_t>, char_encoding_id id) const;
Return value

this->data->transcoder_finder_to_wchar(id) if such function pointer is not null. Otherwise returns dynamic_transcoder<CharT, wchar_t>{}

dynamic_transcoder<wchar_t, CharT> find_transcoder_from
    ( tag<wchar_t>, char_encoding_id id) const;
Return value

this->data->transcoder_finder_from_wchar(id) if such function pointer is not null. Otherwise returns dynamic_transcoder<wchar_t, CharT>{}

7.13. Function template find_transcoder

template <typename SrcEncoding, typename DestEncoding>
auto find_transcoder(SrcEncoding src, DestEncoding dest);
Requirements

SrcEncoding and DestEncoding are CharEncoding types.

Return type

A type that is Transcoder

Return value
  • Returns the default value of static_transcoder<SrcID, DestID> if such template instantiation is defined and SrcEncoding is ( or derives from ) static_char_encoding<SrcID> and DestEncoding is ( or derives from ) static_char_encoding<DestID>;

  • otherwise, returns src.sanitizer() if src.id() is equal to dest.id() and SrcEncoding::char_type is the same type as DestEncoding::char_type;

  • otherwise, returns src.to_u32() if DestEncoding::char_type is char32_t;

  • otherwise, returns dest.from_u32() if SrcEncoding::char_type is char32_t;

  • otherwise, returns src.find_transcoder_to(dest_ch, dest.id()) if such expression is well formed and returns a non null transcoder , where dest_ch is tag<DestEncoding::char_type>{}

  • otherwise, returns dest.find_transcoder_from(src_ch, src.id()) if such expression is well formed, where src_sh is tag<SrcEncoding::char_type>{}

  • otherwise returns dynamic_transcoder<SrcEncoding::char_type, DestEncoding::char_type>{}.

When find_transcoder returns an null transcoder , you still can use decode_encode and decode_encode_size.

7.14. Function template decode_encode

namespace strf {

template<typename SrcCharT, typename DestCharT>
void decode_encode
    ( basic_outbuff<DestCharT>& ob
    , transcode_f<SrcCharT, char32_t> to_u32
    , transcode_f<char32_t, DestCharT> from_u32
    , const SrcCharT* src
    , std::size_t src_size
    , invalid_seq_notifier inv_seq_notifier
    , surrogate_policy surr_poli );

} // namespace strf

Converts the content in src to UTF-32 using to_u32, then writes the result to ob using from_u32.

Postcondition

ob.recycle() is not called if ob.size() is not less then the value returned by decode_encode_size(to_u32, size_calc_func, src, src_size, inv_seq_notifier, surr_poli), where size_calc_func is the return value of dest_enc.from_u32().transcode_size_func(), where dest_enc is the CharEncoding object such that the return value of dest_enc.to_u32().transcode_func() is equal to to_u32.

7.15. Function template decode_encode_size

namespace strf {

template<typename SrcCharT>
std::size_t decode_encode_size
    ( transcode_f<SrcCharT, char32_t> to_u32
    , transcode_size_f<char32_t> size_calc_func
    , const SrcCharT* src
    , std::size_t src_size
    , invalid_seq_notifier inv_seq_notifier
    , surrogate_policy surr_poli );

} // namespace strf
Return value

The return of size_calc_func called over the UTF-32 content obtained by passing src to to_u32.

7.16. Type aliases for encodings

namespace strf {

template <typename CharT>
using ascii = static_char_encoding<CharT, eid_ascii>;

template <typename CharT>
using iso_8859_1 = static_char_encoding<CharT, eid_iso_8859_1>;

template <typename CharT>
using iso_8859_3 = static_char_encoding<CharT, eid_iso_8859_3>;

template <typename CharT>
using iso_8859_15 = static_char_encoding<CharT, eid_iso_8859_15>;

template <typename CharT>
using windows_1252 = static_char_encoding<CharT, eid_windows_1252>;

template <typename CharT>
using utf8 = static_char_encoding<CharT, eid_utf8>;

template <typename CharT>
using utf16 = static_char_encoding<CharT, eid_utf16>;

template <typename CharT>
using utf32 = static_char_encoding<CharT, eid_utf32>;

template <typename CharT>
using utf = /* see below */;

} // namespace strf
template <typename CharT>
using utf = /* ... */;

utf<CharT> is an alias to utf8<CharT>, utf16<CharT> or utf32<CharT>, depending on the value of sizeof(CharT).

8. Width Calculation

8.1. Facet category width_calculator_c

namespace strf {

struct width_calculator_c
{
    static constexpr bool constrainable = true;

    static constexpr fast_width get_default() noexcept;
};

} // namespace strf

For a type to be a facet of the width_calculator_c category, it has to satisfy the WidthCalculator requirements.

Type requirement WidthCalculator

Given

  • CharT, one of the types: char, char8_t, char16_t, char32_t or wchar_t

  • Encoding, an CharEncoding type for value CharSize

  • encoding, an lvalue reference of type Encoding

  • ch a value of type CharT

  • limit, a value of type width_t

  • str, a value of type const CharT* pointing to a string encoded according to encoding.

  • str_len, a value of type std::size_t equal to the length of string str.

  • surr_poli, a value of type surrogate_policy

For a type X to be WidthCalculator, given an object x of type X, the following syntax and requirements have to be satisfied:

X::category

A type alias to width_calculator_c.

x.char_width(encoding, ch)
Return type

width_t

Return value

The width of ch when encoded according to encoding.

x.str_width(encoding, limit, str, str_len, surr_poli)
Return type

width_t

Return value

The width of the string str if it is less than limit. Otherwise, it can be any value that is greater than or equal to limit.

x.str_width_and_pos(encoding, limit, str, str_len, surr_poli)
Effect

Calculates the width of str. If such value is less than limit, then calculates the size of the substring of str whose width is equal to limit.

Return type

width_and_pos

Return value

A value ret of type width_and_pos, such that

  • ret.pos is the greatest value that is less than or equal to str_len such that x.width(encoding, width_max, str, ret.pos, surr_poli).width is less than or equal to limit.

  • ret.width is the width of the substring of str with size ret.pos that starts at the same position of str.

The library provides three classes and one class template that satisfy _WidthCalculator: fast_width, width_as_fast_u32len, width_as_u32len and `width_by_func.

Struct width_and_pos

struct width_and_pos {
    width_t width;
    std::size_t pos;
};

8.2. Class fast_width

Class fast_width is a facet of the category width_calculator_c that evaluates the width of a string as its size.

class fast_width final
{
public:
    using category = width_calculator_c;

    template <typename CharEncoding>
    width_t char_width
        ( CharEncoding
        , typename CharEncoding::char_type ) const noexcept;

    template <typename CharEncoding>
    width_t str_width
        ( CharEncoding
        , width_t limit
        , const typename CharEncoding::char_type*
        , std::size_t str_len
        , surrogate_policy ) const noexcept;

    template <typename CharEncoding>
    constexpr width_and_pos str_width_and_pos
        ( CharEncoding
        , width_t limit
        , const typename CharEncoding::char_type*
        , std::size_t str_len
        , surrogate_policy ) const noexcept;
};
template <typename CharEncoding>
width_t char_width
    ( CharEncoding
    , typename CharEncoding::char_type ) const noexcept;
Return value

1

template <typename CharEncoding>
constexpr width_t str_width
    ( CharEncoding
    , width_t limit
    , const typename CharEncoding::char_type*
    , std::size_t str_len
    , surrogate_policy ) const noexcept;
Return value
  • str_len, if str_len is less than or equal to limit.floor()

  • otherwise, limit

template <typename CharEncoding>
constexpr width_and_pos str_width_and_pos
    ( CharEncoding
    , width_t limit
    , const typename CharEncoding::char_type*
    , std::size_t str_len
    , surrogate_policy ) const noexcept;
Return value

The return value ret is such that

  • if limit <= 0 is true, then ret.width and ret.pos are 0;

  • otherwise, if limit.floor() is less than str_len, then ret.width and ret.pos are equal to limit.floor();

  • otherwise, ret.width and ret.pos are equal to str_len.

8.3. Class width_as_fast_u32len

Class width_as_fast_u32len is a facet of the category width_calculator_c. It evaluates the width of a string as the number of Unicode code points. However, to gain performance and differently from width_as_u32len, it assumes that the measured string is totally conformant to its encoding.

class width_as_fast_u32len final
{
public:
    using category = width_calculator_c;

    template <typename CharEncoding>
    width_t char_width
        ( CharEncoding encoding
        , typename CharEncoding::char_type ) const noexcept;

    template <typename CharEncoding>
    width_t str_width
        ( CharEncoding encoding
        , width_t limit
        , const typename CharEncoding::char_type* str
        , std::size_t str_len
        , surrogate_policy ) const noexcept;

    template <typename CharEncoding>
    constexpr width_and_pos str_width_and_pos
        ( CharEncoding encoding
        , width_t limit
        , const typename CharEncoding::char_type* str
        , std::size_t str_len
        , surrogate_policy ) const noexcept;
};
template <typename CharEncoding>
width_t char_width
    ( CharEncoding
    , typename CharEncoding::char_type ) const noexcept;
Return value

1

template <typename CharEncoding>
constexpr width_t str_width
    ( CharEncoding encoding
    , width_t limit
    , const typename CharEncoding::char_type* str
    , std::size_t str_len
    , surrogate_policy ) const noexcept;
Return value
template <typename CharEncoding>
constexpr width_and_pos str_width_and_pos
    ( CharEncoding encoding
    , width_t limit
    , const typename CharEncoding::char_type* str
    , std::size_t str_len
    , surrogate_policy ) const noexcept;
Return value

The return value ret is such that

  • If limit <= 0 is true, then then ret.width and ret.pos are 0;

  • otherwise, ret.width is equal to ret2.count and ret.pos is equal to encoding.codepoints_fast_count(str, str_len, lim).pos

8.4. Class width_as_u32len

Class width_as_fast_u32len is a facet of the category width_calculator_c. It evaluates the width of a string as the number of Unicode code points, assuming that any non-conformity to the corresponding encoding is replaced by one codepoint ( following the semantics of {invalid_seq_policy}::replace ).

class width_as_u32len final
{
public:
    using category = width_calculator_c;

    template <typename CharEncoding>
    width_t char_width
        ( CharEncoding encoding
        , typename CharEncoding::char_type ) const noexcept;

    template <typename CharEncoding>
    width_t str_width
        ( CharEncoding encoding
        , width_t limit
        , const typename CharEncoding::char_type* str
        , std::size_t str_len
        , surrogate_policy ) const noexcept;

    template <typename CharEncoding>
    constexpr width_and_pos str_width_and_pos
        ( CharEncoding encoding
        , width_t limit
        , const typename CharEncoding::char_type* str
        , std::size_t str_len
        , surrogate_policy ) const noexcept;
};
template <typename CharEncoding>
width_t char_width
    ( CharEncoding
    , typename CharEncoding::char_type ) const noexcept;
Return value

1

template <typename CharEncoding>
constexpr width_t str_width
    ( CharEncoding encoding
    , width_t limit
    , const typename CharEncoding::char_type* str
    , std::size_t str_len
    , surrogate_policy ) const noexcept;
Return value
template <typename CharEncoding>
constexpr width_and_pos str_width_and_pos
    ( CharEncoding encoding
    , width_t limit
    , const typename CharEncoding::char_type* str
    , std::size_t str_len
    , surrogate_policy ) const noexcept;
Return value

The return value ret is such that

  • If limit <= 0 is true, then then ret.width and ret.pos are 0;

  • otherwise, ret.width is equal to ret2.count and ret.pos is equal to encoding.codepoints_robust_count(str, str_len, lim).pos

8.5. Class template width_by_func

The instances of the width_by_func class template are facets of the category width_calculator_c. It calculates the width of a string by converting it to UTF-32, following the policy associated to {invalid_seq_policy}::replace, and then calling the provided function to evaluate the width of each UTF-32 character.

template <typename CharWidthFunc>
class width_by_func{
public:
    using category = width_calculator_c;

    template <typename CharEncoding>
    width_t char_width
        ( CharEncoding charste
        , typename CharEncoding::char_type ) const;

    template <typename CharEncoding>
    width_t str_width
        ( CharEncoding encoding
        , width_t limit
        , const typename CharEncoding::char_type* str
        , std::size_t str_len
        , surrogate_policy ) const;

    template <typename CharEncoding>
    constexpr width_and_pos str_width_and_pos
        ( CharEncoding encoding
        , width_t limit
        , const typename CharEncoding::char_type* str
        , std::size_t str_len
        , surrogate_policy ) const;

private:

    const CharWidthFunc func_; // exposition only
};

Compile-time requirements

Given

  • ch, a value of type char32_t

  • func, a object of type CharWidthFunc or const CharWidthFunc

The expression func(ch) must be well formed and the return type must be width_t.

Member functions

template <typename CharEncoding>
width_t char_width
    ( CharEncoding encoding
    , typename CharEncoding::char_type ch) const;
Return value

func_(encoding.decode_char(ch))

template <typename CharEncoding>
constexpr width_t str_width
    ( CharEncoding encoding
    , width_t limit
    , const typename CharEncoding::char_type* str
    , std::size_t str_len
    , surrogate_policy  surr_poli) const;
Return value

The sum of the values of func_(ch32), where ch32 is each of the char32_t values that are written into ob — an object whose type derives from basic_outbuff<char32_t> — by the call

encoding.to_u32().transcode
    ( ob, str, str_len, {invalid_seq_policy}::replace, surr_poli )

, if such value is less than or equal to limit. Otherwise, the return value can be anyone that is greater than or equal to limit.

template <typename CharEncoding>
constexpr width_and_pos str_width_and_pos
    ( CharEncoding encoding
    , width_t limit
    , const typename CharEncoding::char_type* str
    , std::size_t str_len
    , surrogate_policy surr_poli) const;
Return value

The return value ret is such that:

  • ret.width is the sum of the values of func_(ch32), where ch32 is each of the char32_t values that are written into ob by the call

    encoding.to_u32().transcode
        ( ob, str, ret.pos, {invalid_seq_policy}::replace, surr_poli )

    , where ob is any object whose type derives from basic_outbuff<char32_t>.

  • ret.pos is the greatest value that is less than or equal to str_len such that str_width_and_pos(encoding, limit, str, ret.pos, surr_poli).width is less than or equal to limit.

8.6. Function template make_width_calculator

template <typename CharWidthFunc>
width_by_func<CharWidthFunc> make_width_calculator(CharWidthFunc f);
Return value

width_by_func<CharWidthFunc>{f}

8.7. Class width_t

The width_t class implements signed Q16.16 arithmetics and is used to represent width of textual content when text alignment formatting is used. The value of width_t(1) corresponds to an en.

namespace strf {

class width_t {
public:
    struct from_underlying_tag{};
    constexpr width_t() noexcept;
    constexpr width_t(std::int16_t) noexcept;
    constexpr width_t(const width_t&) noexcept;
    constexpr width_t(from_underlying_tag, std::int32_t) noexcept;

    constexpr width_t& operator=(const width_t& other) noexcept;
    constexpr width_t& operator=(std::int16_t& x) noexcept;

    constexpr bool operator==(const width_t& other) const noexcept;
    constexpr bool operator!=(const width_t& other) const noexcept;
    constexpr bool operator<(const width_t& other) const noexcept;
    constexpr bool operator>(const width_t& other) const noexcept;
    constexpr bool operator<=(const width_t& other) const noexcept;
    constexpr bool operator>=(const width_t& other) const noexcept;

    constexpr bool is_integral() const noexcept;
    constexpr std::int16_t floor() const noexcept;
    constexpr std::int16_t ceil() const noexcept;
    constexpr std::int16_t round() const noexcept;

    constexpr width_t operator-() const noexcept;
    constexpr width_t operator+() const noexcept;
    constexpr width_t& operator+=(width_t other) noexcept;
    constexpr width_t& operator-=(width_t other) noexcept;
    constexpr width_t& operator*=(std::int16_t m) noexcept;
    constexpr width_t& operator/=(std::int16_t d) noexcept;
    constexpr width_t& operator*=(width_t other) noexcept;
    constexpr width_t& operator/=(width_t other) noexcept;

    constexpr std::int32_t underlying_value() const noexcept;
    constexpr static width_t from_underlying(std::int32_t) noexcept;

private:
    std::int32_t _underlying_value; // exposition only
};

constexpr width_t width_max = width_t::from_underlying(INT32_MAX);
constexpr width_t width_min = width_t::from_underlying(INT32_MIN);

constexpr bool operator==(width_t lhs, std::int16_t rhs) noexcept;
constexpr bool operator==(std::int16_t lhs, width_t rhs) noexcept;
constexpr bool operator!=(width_t lhs, std::int16_t rhs) noexcept;
constexpr bool operator!=(std::int16_t lhs, width_t rhs) noexcept;
constexpr bool operator< (width_t lhs, std::int16_t rhs) noexcept;
constexpr bool operator< (std::int16_t lhs, width_t rhs) noexcept;
constexpr bool operator<=(width_t lhs, std::int16_t rhs) noexcept;
constexpr bool operator<=(std::int16_t lhs, width_t rhs) noexcept;
constexpr bool operator> (width_t lhs, std::int16_t rhs) noexcept;
constexpr bool operator> (std::int16_t lhs, width_t rhs) noexcept;
constexpr bool operator>=(width_t lhs, std::int16_t rhs) noexcept;
constexpr bool operator>=(std::int16_t lhs, width_t rhs) noexcept;

constexpr width_t operator+(width_t lhs, width_t rhs) noexcept;
constexpr width_t operator+(std::int16_t lhs, width_t rhs) noexcept;
constexpr width_t operator+(width_t lhs, std::int16_t rhs) noexcept;
constexpr width_t operator-(width_t lhs, width_t rhs) noexcept;
constexpr width_t operator-(std::int16_t lhs, width_t rhs) noexcept;
constexpr width_t operator-(width_t lhs, std::int16_t rhs) noexcept;
constexpr width_t operator*(width_t lhs, width_t rhs) noexcept;
constexpr width_t operator*(std::int16_t lhs, width_t rhs) noexcept;
constexpr width_t operator*(width_t lhs, std::int16_t rhs) noexcept;
constexpr width_t operator/(width_t lhs, width_t rhs) noexcept;
constexpr width_t operator/(std::int16_t lhs, width_t rhs) noexcept;
constexpr width_t operator/(width_t lhs, std::int16_t rhs) noexcept;

constexpr width_t checked_add(width_t lhs, width_t rhs) noexcept;
constexpr width_t checked_subtract(width_t lhs, std::int64_t rhs) noexcept;
constexpr width_t checked_subtract(width_t lhs, width_t rhs) noexcept;
constexpr width_t checked_mul(width_t lhs, std::uint32_t rhs) noexcept;

} // namespace strf

to-do

8.8. width_t literal _w

namespace strf {
namespace width_literal {

template <char...C>
constexpr width_t operator "" _w()

} // namespace width_literal
} // namespace strf

The suffix _w can be aplied in floating-points literals in fixed notations as well as integer literals.

Example
using namespace strf::width_literal;

strf::width_t x = 1.5_w;
x += 0.25_w;
x += 1_w;
assert(x == 2.75_w);

9. Numeric punctuation

To-do

10. Miscellaneous

10.1. The lettercase facet

namespace strf {

enum class lettercase { lower = /*...*/, mixed = /*...*/, upper = /*...*/ };

constexpr lettercase lowercase = lettercase::lower;
constexpr lettercase mixedcase = lettercase::mixed;
constexpr lettercase uppercase = lettercase::upper;

struct lettercase_c {
    static constexpr bool constrainable = true;
    constexpr static lettercase get_default() noexcept
    {
        return lettercase::lower;
    }
};

template <>
struct {facet_traits}<lettercase> {
    using category = lettercase_c;
};

} // namespace strf

10.2. Type traits

The table below list class templates that satisfy UnaryTypeTrait. They are created to be used in the constrain function template to filter printable types.

is_int_number

matches short, int, long, long long and the corresponding unsigned types

is_char

matches char, char8_t, wchar_t, char16_t, and char32_t

is_string

matches strings.

to-do

10.3. Class template tag

namespace strf {

template <typename... >
struct tag
{
    explicit tag() = default;
};

template <typename T>
struct tag<T>
{
    explicit constexpr STRF_HD tag() noexcept { }
    using type = T;
};

} // namespace strf

10.4. Outbuff writing functions

namespace strf {

template <std::size_t CharSize>
void write( underlying_outbuff<CharSize>& ob
          , const underlying_char_type<CharSize>* data
          , std::size_t data_size );

template <std::size_t CharSize>
void write( underlying_outbuff<CharSize>& ob
          , const underlying_char_type<CharSize>* data
          , const underlying_char_type<CharSize>* data_end );

template <typename CharT>
void write( basic_outbuff<CharT>& ob
          , const CharT* data
          , std::size_t count );

template <typename CharT>
void write( basic_outbuff<CharT>& ob
          , const CharT* data
          , const CharT* data_end );

void write(basic_outbuff<char>& ob, const char* cstr);

void write(basic_outbuff<wchar_t>& ob, const wchar_t* cstr);

} // namespace strf
template <std::size_t CharSize>
void write( underlying_outbuff<CharSize>& ob
          , const underlying_char_type<CharSize>* data
          , const underlying_char_type<CharSize>* data_end );
Effect

Writes the the range [ data, data_end ) into ob, calling ob.recycle() how many times are necessary.

template <std::size_t CharSize>
void write( underlying_outbuff<CharSize>& ob
          , const underlying_char_type<CharSize>* data
          , std::size_t data_size );
Effect

Same as write(ob, data, data + data_size)

template <typename CharT>
void write( {basic_outbuff}<CharT>& ob
          , const CharT* data
          , const CharT* data_end );
Effect

Writes the the range [ data, data_end ) into ob, calling ob.recycle() how many times are necessary.

template <typename CharT>
void write( {basic_outbuff}<CharT>& ob
          , const CharT* data
          , std::size_t data_size );
Effect

Same as write(ob, data, data + data_size)

void write( {basic_outbuff}<char>& ob
          , const char* cstr );
Effect

Same as write(ob, cstr, std::strlen(cstr))

void write( basic_outbuff<wchar_t>& ob
          , const wchar_t* wcstr );
Effect

Same as write(ob, wcstr, std::wstrlen(wcstr))

10.5. Destination markers

namespace strf {

/* see below */ to(char8_t*  dest, std::size_t count);
/* see below */ to(char*     dest, std::size_t count);
/* see below */ to(char16_t* dest, std::size_t count);
/* see below */ to(char32_t* dest, std::size_t count);
/* see below */ to(wchar_t*  dest, std::size_t count);

} // namespace strf
Return type

destination_no_reserve<OBC>, where OBC is an implementation-defined type that satifies OutbuffCreator.

Return value

A destination object whose internal OutbuffCreator object obc is such that obc.create() returns a basic_cstr_writer<CharT> object initialized with dest and count, where, CharT is std::remove_reference_t<decltype(*dest)>.

namespace strf {

template<std::size_t N> /* see below */ to(char8_t  (&dest)[N]);
template<std::size_t N> /* see below */ to(char     (&dest)[N]);
template<std::size_t N> /* see below */ to(char16_t (&dest)[N]);
template<std::size_t N> /* see below */ to(char32_t (&dest)[N]);
template<std::size_t N> /* see below */ to(wchar_t  (&dest)[N]);

} // namespace strf
Return type and value

Same as to(dest, N);

namespace strf {

/* see below */ to(char8_t*  dest,  char8_t*  end);
/* see below */ to(char*     dest,  char*     end);
/* see below */ to(char16_t* dest,  char16_t* end);
/* see below */ to(char32_t* dest,  char32_t* end);
/* see below */ to(wchar_t*  dest,  wchar_t*  end);

} // namespace strf
Return type and value

Same as to(dest, (std::size_t)(end - dest));

10.6. Alignment format functions

Text aligment format function
operator>(std::int16_t width)

Align to the right ( Or to the left right-to-left (RTL) script )

operator<(std::int16_t width)

Align to the left ( Or to the right right-to-left (RTL) script )

operator^(std::int16_t width)

Center alignment

operator%(std::int16_t width)

Split the content, as in std::internal.

fill(char32_t ch)

Set the fill character.