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.

1.1.1. 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.

1.6.1. 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

1.6.2. 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 */;
};

1.12.1. Public members

typename /* */ category;

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

1.12.2. 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. 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.

2.1. Class template destination_no_reserve

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

2.1.1. 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

2.1.2. 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/get the outbuff object doing

    decltype(auto) ob = _outbuff_creator.create()
  2. For each arg in args..., creates a printer object by doing:

    auto p = static_cast< const {printer}<sizeof(CharT)>& >
        ( printer_impl<CharT, FPack, T>{fpack, preview, x, chtag} )

    , where preview is an instance of print_preview<preview_size::no, preview_width::no> , and chtag is an expression of type tag<CharT>.

  3. For each p object does p.print_to(ob)

  4. 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

2.2. Class template destination_calc_size

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

2.2.1. 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>.

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

    auto p = static_cast< const {printer}<sizeof(CharT)>& >
        ( printer_impl<CharT, FPack, T>{ _fpack, preview, arg, tag<CharT>{} } )
  3. Creates/get the outbuff object doing

    decltype(auto) ob = _outbuff_creator.create(preview.get_size())
  4. For each p object does 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

2.3. Class template destination_with_given_size

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

2.3.1. 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..., creates a printer object by doing:

    auto p = static_cast< const {printer}<sizeof(CharT)>& >
        ( printer_impl<CharT, FPack, T>{fpack, preview, x, chtag} )

    , where preview is an instance of preview<false, false>, and chtag is an expression of type tag<CharT>.

  3. For each p object does p.print_to(ob)

  4. 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

2.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:

And the following expression must be satisfied:

x.create()
Return value

A type that derives from basic_outbuff<char_type>

2.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:

And the following expression must be satisfied:

x.create(size)
Return type

A type that derives from basic_outbuff<char_type>

Postcondition

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

3. Tr-String

3.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

3.1.1. 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}");

3.1.2. 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.

3.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

3.2.1. 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

3.2.2. Type requirement TrErrorHandling

Given:

  • X, a TrErrorHandling type

  • x, a value of type X

  • Enc, a CharEncodingFacet 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.

4. 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

4.7.1. 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)");

4.7.2. 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

4.8.1. Without alignment

namespace strf {

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

}

4.8.2. 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. Character encodings

5.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

5.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

5.2.1. 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.

5.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;
};

5.3.1. Semantics

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

5.4. Aliases for pointers to functions

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

template <std::size_t SrcCharSize, std::size_t DestCharSize>
using transcode_f = void (*)
    ( underlying_outbuff<DestCharSize>& ob
    , const underlying_char_type<SrcCharSize>* src
    , std::size_t src_size
    , invalid_seq_notifier inv_seq_notifier
    , surrogate_policy surr_poli );

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

template <std::size_t CharSize>
using write_replacement_char_f = void (*) ( underlying_outbuff<CharSize>& );

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

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

template <std::size_t CharSize>
using encode_char_f = underlying_char_type<CharSize>*(*)
    ( underlying_char_type<CharSize>* dest, char32_t ch );

template <std::size_t CharSize>
using encode_fill_f = void (*)
    ( underlying_outbuff<CharSize>&, std::size_t count, char32_t ch );

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

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

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

template <std::size_t CharSize>
using decode_char_f = char32_t (*) ( underlying_char_type<CharSize> );

template <std::size_t SrcCharSize, std::size_t DestCharSize>
using find_transcoder_f =
    dynamic_underlying_transcoder<SrcCharSize, DestCharSize> (*) ( char_encoding_id );

5.5. Type requirement UnderlyingTranscoder

Given

  • SrcCharSize, a constexpr std::size_t value equal to 1, 2 or 4

  • DestCharSize, a constexpr std::size_t value equal to 1, 2 or 4

  • SrcCharType, the type of underlying_char_type<SrcCharSize>

  • X, a UnderlyingTranscoder type from SrcCharSize to DestCharSize

  • x, an expression of type X or const X

  • dest, an lvalue reference of type underlying_outbuff<DestCharSize>

  • src, a value of type const SrcCharType*

  • 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<SrcCharSize>

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<SrcCharSize, DestCharSize>

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 UnderlyingTranscoder type where the transcode_func function returns nullptr.

There are two class templates that satisfy UnderlyingTranscoder: static_underlying_transcoder and dynamic_underlying_transcoder.

5.6. Type requirement UnderlyingCharEncoding

Given

  • CharSize, a constexpr std::size_t value equal to 1, 2, or ( UTF-32 only ) 4

  • char_type, the type of underlying_char_type<CharSize>&

  • ptr, a value of type char_type*

  • src, a value of type const char_type*

  • 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 char_type

  • ob, an lvalue reference of type underlying_outbuff<CharSize>

  • enc_id, value of type char_encoding_id

  • X, a UnderlyingCharEncoding type for value CharSize

  • x, an expression of type X or const X

X must be CopyConstructible and satisfy the expressions below:

X::char_size
Type

std::size_t

Value

CharSize

Note

It is constexpr.

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

char_type*

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<CharSize>

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<CharSize>

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<CharSize>

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 UnderlyingTranscoder from 4 to CharSize

Return value

A transcoder that converts UTF-32 to this encoding.

x.to_u32()
Return type

A UnderlyingTranscoder from CharSize to 4

Return value

A transcoder that converts this encoding to UTF-32.

x.sanitizer()
Return type

A UnderlyingTranscoder from CharSize to CharSize

Return value

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

( Optional )
x.find_transcoder_to(std::integral_constant<std::size_t, 1>, enc_id)
Return type

dynamic_underlying_transcoder<CharSize, 1>

Return value

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

( Optional )
x.find_transcoder_to(std::integral_constant<std::size_t, 2>, enc_id)
Return type

dynamic_underlying_transcoder<CharSize, 2>

Return value

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

( Optional )
x.find_transcoder_from<ScrCharSize>(std::integral_constant<std::size_t, 1>, enc_id)
Return type

dynamic_underlying_transcoder<1, CharSize>

Return value

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

( Optional )
x.find_transcoder_from<ScrCharSize>(std::integral_constant<std::size_t, 1>, enc_id)
Return type

dynamic_underlying_transcoder<2, CharSize>

Return value

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

You shall not create an UnderlyingCharEncoding type with CharSize equal to 4, since this is reserved for UTF-32. The library internaly assumes in many occasions that the encoding is UTF-32 when CharSize is equal to 4.
There are two class templates that satisfy UnderlyingCharEncoding: static_underlying_transcoder and dynamic_underlying_char_encoding.

5.7. Class template static_underlying_transcoder

template <char_encoding_id Src, char_encoding_id Dest>
class static_underlying_transcoder;

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

There is no generic implementation of the static_underlying_transcoder class template. Instead, there are only template specializations for some pairs of encodings. All of them are empty classes, and are UnderlyingTranscoder, and their member functions transcode_func and transcode_size_func never return nullptr

5.8. Class template static_underlying_char_encoding

template <char_encoding_id>
class static_underlying_char_encoding;

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

There is no generic implementation of the static_underlying_char_encoding class template. Instead, the library provides template specializations for some encodings. All of them are empty classes, and are UnderlyingCharEncoding.

5.9. Class template dynamic_underlying_transcoder

namespace strf {

template <std::size_t SrcCharSize, std::size_t DestCharSize>
class dynamic_underlying_transcoder {
public:
    constexpr dynamic_underlying_transcoder() noexcept;

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

    template <char_encoding_id Src, char_encoding_id Dest>
    constexpr explicit dynamic_underlying_transcoder
        ( static_underlying_transcoder<Src, Dest> st );

    void transcode
        ( underlying_outbuff<DestCharSize>& ob
        , const underlying_char_type<SrcCharSize>* src
        , std::size_t src_size
        , invalid_seq_notifier inv_seq_notifier
        , surrogate_policy surr_poli ) const;

    std::size_t transcode_size
        ( const underlying_char_type<SrcCharSize>* src
        , std::size_t src_size
        , surrogate_policy surr_poli ) const;

    constexpr transcode_f<SrcCharSize, DestCharSize> transcode_func() const noexcept;
    constexpr transcode_size_f<SrcCharSize> transcode_size_func() const noexcept;
};

} // namespace strf
constexpr dynamic_underlying_transcoder() noexcept;

Default constructor

Postconditions
  • transcode_func() == nullptr

  • transcode_size_func() == nullptr

constexpr dynamic_underlying_transcoder
    ( const dynamic_underlying_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_underlying_transcoder
    ( static_underlying_transcoder<Src, Dest> other );
Postconditions
  • transcode_func() == other.transcode_func()

  • transcode_size_func() == other.transcode_size_func()

void transcode
    ( underlying_outbuff<DestCharSize>& ob
    , const underlying_char_type<SrcCharSize>* 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 underlying_char_type<SrcCharSize>* src
    , std::size_t src_size
    , surrogate_policy surr_poli ) const;

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

5.10. Struct template dynamic_underlying_char_encoding_data

template <std::size_t CharSize>
struct dynamic_underlying_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<CharSize> encode_char_func;
    encode_fill_f<CharSize> encode_fill_func;
    codepoints_fast_count_f<CharSize> codepoints_fast_count_func;
    codepoints_robust_count_f<CharSize> codepoints_robust_count_func;

    write_replacement_char_f<CharSize> write_replacement_char_func;
    decode_char_f<CharSize> decode_char_func;

    dynamic_underlying_transcoder<4, CharSize> from_u32;
    dynamic_underlying_transcoder<CharSize, 4> to_u32;
    dynamic_underlying_transcoder<CharSize, CharSize> sanitizer;

    find_transcoder_f<1, CharSize> transcoder_from_1byte_encoding;
    find_transcoder_f<2, CharSize> transcoder_from_2bytes_encoding;

    find_transcoder_f<CharSize, 1> transcoder_to_1byte_encoding;
    find_transcoder_f<CharSize, 2> transcoder_to_2bytes_encoding;
};

5.11. Class template dynamic_underlying_char_encoding

template <std::size_t CharSize>
class dynamic_underlying_char_encoding {
public:

    static constexpr std::size_t char_size = CharSize;

    dynamic_underlying_char_encoding(const dynamic_underlying_char_encoding& other) = default;

    dynamic_underlying_char_encoding
        ( const dynamic_underlying_char_encoding_data<CharSize>& d );

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

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

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

    void swap(dynamic_underlying_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
        ( underlying_outbuff<CharSize>& 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(underlying_outbuff<CharSize>& ob) const;

    char32_t decode_char(char_type_ ch) const;

    encode_char_f<char_size> encode_char_func() const noexcept;

    encode_fill_f<char_size> encode_fill_func() const noexcept;

    write_replacement_char_f<char_size> write_replacement_char_func() const noexcept;

    dynamic_underlying_transcoder<4, CharSize> from_u32() const;

    dynamic_underlying_transcoder<CharSize, 4> to_u32() const;

    dynamic_underlying_transcoder<CharSize, CharSize> sanitizer() const;

    dynamic_underlying_transcoder<CharSize, 1> find_transcoder_to
        ( std::integral_constant<std::size_t, 1>, char_encoding_id id) const;

    dynamic_underlying_transcoder<CharSize, 2> find_transcoder_to
        ( std::integral_constant<std::size_t, 2>, char_encoding_id id) const;

    dynamic_underlying_transcoder<1, CharSize> find_transcoder_from
        ( std::integral_constant<std::size_t, 1>, char_encoding_id id) const;

    dynamic_underlying_transcoder<2, CharSize> find_transcoder_from
        ( std::integral_constant<std::size_t, 2>, char_encoding_id id) const;

private:

    const dynamic_underlying_char_encoding_data* data; // exposition only
};
dynamic_underlying_char_encoding(const dynamic_underlying_char_encoding& other);

Trivial copy constructor.

Effect

this->data = other.data

dynamic_underlying_char_encoding
        ( const dynamic_underlying_char_encoding_data<CharSize>& d );
Effect

this->data = d

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

this->data = other.data

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

this->data == other.data

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

this->data != other.data

void swap(dynamic_underlying_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
    ( underlying_outbuff<CharSize>& 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(underlying_outbuff<CharSize>& 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<char_size> encode_char_func() const noexcept;
encode_fill_f<char_size> encode_fill_func() const noexcept;
Return value

this->data->encode_fill_func.

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

this->data->write_replacement_char_func.

dynamic_underlying_transcoder<4, CharSize> from_u32() const;
Return value

this->data->from_u32.

dynamic_underlying_transcoder<CharSize, 4> to_u32() const;
Return value

this->data->to_u32.

dynamic_underlying_transcoder<CharSize, CharSize> sanitizer() const;
Return value

this->data->sanitizer.

dynamic_underlying_transcoder<CharSize, 1> find_transcoder_to
    ( std::integral_constant<std::size_t, 1>, char_encoding_id id) const;
Return value

this->data->transcoder_to_1byte_char_encoding(id) if such pointer to function is not null. Otherwise returns an null transcoder.

dynamic_underlying_transcoder<CharSize, 2> find_transcoder_to
    ( std::integral_constant<std::size_t, 2>, char_encoding_id id) const;
Return value

this->data->transcoder_to_2bytes_char_encoding(id) if such pointer to function is not null. Otherwise returns an null transcoder.

dynamic_underlying_transcoder<1, CharSize> find_transcoder_from
    ( std::integral_constant<std::size_t, 1>, char_encoding_id id) const;
Return value

this->data->transcoder_from_1byte_char_encoding(id) if such pointer to function is not null. Otherwise returns an null transcoder.

dynamic_underlying_transcoder<2, CharSize> find_transcoder_from
    ( std::integral_constant<std::size_t, 2>, char_encoding_id id) const;
Return value

this->data->transcoder_from_2bytes_char_encoding(id) if such pointer to function is not null. Otherwise returns an null transcoder.

5.12. Function template find_transcoder

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

SrcEncoding and DestEncoding are UnderlyingCharEncoding types.

Return type

A type that is UnderlyingTranscoder

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

  • otherwise, returns src.sanitizer() if src.id() is equal to dest.id() and SrcEncoding::char_size is equal to DestEncoding::char_size;

  • otherwise, returns src.to_u32() if DestEncoding::char_size is equal to 4;

  • otherwise, returns dest.from_u32() if SrcEncoding::char_size is equal to 4;

  • otherwise, returns src.find_transcoder_to(x, dest.id()) if such expression is well formed and returns a non null transcoder , where x is the value of std::integral_constant<std::size_t, DestEncoding::char_size>();

  • otherwise, returns dest.find_transcoder_from(x, src.id()) if such expression is well formed, where x is the value of std::integral_constant<std::size_t, SrcEncoding::char_size>();

  • otherwise returns a default constructed ( thus null ) dynamic_underlying_transcoder<SrcEncoding::char_size, DestEncoding::char_size>.

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

5.13. Function template decode_encode

namespace strf {

template<std::size_t SrcCharSize, std::size_t DestCharSize>
void decode_encode
    ( underlying_outbuff<DestCharSize>& ob
    , transcode_f<SrcCharSize, 4> to_u32
    , transcode_f<4, DestCharSize> from_u32
    , const underlying_char_type<SrcCharSize>* 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 it into 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 UnderlyingCharEncoding object such that the return value of dest_enc.to_u32().transcode_func() is equal to to_u32.

5.14. Function template decode_encode_size

namespace strf {

template<std::size_t SrcCharSize>
std::size_t decode_encode_size
    ( transcode_f<SrcCharSize, 4> to_u32
    , transcode_size_f<4> size_calc_func
    , const underlying_char_type<SrcCharSize>* 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.

5.15. 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;
};

} // namespace strf

For a type to be a facet of char_encoding_c<CharT> it has to to be CharEncodingFacet of CharT

5.16. Type requirement CharEncodingFacet

Given:

  • CharT, a character type

  • X, CharEncodingFacet type of CharT

The following must hold:

There are two class templates that satisfy CharEncodingFacet: static_char_encoding and dynamic_char_encoding.

5.17. Class template static_char_encoding

namespace strf {

template <typename CharT, char_encoding_id CSID>
class static_char_encoding: public static_underlying_char_encoding<CSID> {
public:
    static_assert(sizeof(CharT) == static_underlying_char_encoding<CSID>::char_size);
    using category = char_encoding_c<CharT>;
    using char_type = CharT;
};

} // namespace strf

5.18. 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).

5.19. Class template dynamic_char_encoding

namespace strf {

template <typename CharT>
class dynamic_char_encoding: public dynamic_underlying_char_encoding<sizeof(CharT)> {
public:
    using category = char_encoding_c<CharT>;
    using char_type = CharT;

    dynamic_char_encoding(const dynamic_char_encoding&) = default;

    explicit dynamic_char_encoding(const dynamic_underlying_char_encoding<sizeof(CharT)>&);

    template <char_encoding_id EncodingID>
    explicit dynamic_char_encoding(static_char_encoding<CharT, EncodingID> scs);
};

} // namespace strf
dynamic_char_encoding(const dynamic_char_encoding&);

Trivial copy constructor

explicit dynamic_char_encoding(const dynamic_underlying_char_encoding<sizeof(CharT)>& x);
Effect

Initializes base dynamic_underlying_char_encoding<sizeof(CharT)> from x.

template <char_encoding_id EncodingID>
explicit dynamic_char_encoding(static_char_encoding<CharT, EncodingID> enc);
Effect

Initializes base dynamic_underlying_char_encoding<sizeof(CharT)> with enc.to_dynamic().

6. Width Calculation

6.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.

6.1.1. Type requirement WidthCalculator

Given

  • CharSize, an constexpr integer value equal to 1, 2 or 4

  • Encoding, an UnderlyingCharEncoding type for value CharSize

  • encoding, an lvalue reference of type Encoding

  • ch a value of type underlying_char_type<CharSize>

  • limit, a value of type width_t

  • str, a value of type const underlying_char_type<CharSize>* pointing to 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.

6.1.2. Struct width_and_pos

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

6.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
        , underlying_char_type<CharEncoding::char_size> ) const noexcept;

    template <typename CharEncoding>
    width_t str_width
        ( CharEncoding
        , width_t limit
        , const underlying_char_type<CharEncoding::char_size>*
        , 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 underlying_char_type<CharEncoding::char_size>*
        , std::size_t str_len
        , surrogate_policy ) const noexcept;
};
template <typename CharEncoding>
width_t char_width
    ( CharEncoding
    , underlying_char_type<CharEncoding::char_size> ) const noexcept;
Return value

1

template <typename CharEncoding>
constexpr width_t str_width
    ( CharEncoding
    , width_t limit
    , const underlying_char_type<CharEncoding::char_size>*
    , 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 underlying_char_type<CharEncoding::char_size>*
    , 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.

6.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
        , underlying_char_type<CharEncoding::char_size> ) const noexcept;

    template <typename CharEncoding>
    width_t str_width
        ( CharEncoding encoding
        , width_t limit
        , const underlying_char_type<CharEncoding::char_size>* 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 underlying_char_type<CharEncoding::char_size>* str
        , std::size_t str_len
        , surrogate_policy ) const noexcept;
};
template <typename CharEncoding>
width_t char_width
    ( CharEncoding
    , underlying_char_type<CharEncoding::char_size> ) const noexcept;
Return value

1

template <typename CharEncoding>
constexpr width_t str_width
    ( CharEncoding encoding
    , width_t limit
    , const underlying_char_type<CharEncoding::char_size>* 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 underlying_char_type<CharEncoding::char_size>* 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

6.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
        , underlying_char_type<CharEncoding::char_size> ) const noexcept;

    template <typename CharEncoding>
    width_t str_width
        ( CharEncoding encoding
        , width_t limit
        , const underlying_char_type<CharEncoding::char_size>* 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 underlying_char_type<CharEncoding::char_size>* str
        , std::size_t str_len
        , surrogate_policy ) const noexcept;
};
template <typename CharEncoding>
width_t char_width
    ( CharEncoding
    , underlying_char_type<CharEncoding::char_size> ) const noexcept;
Return value

1

template <typename CharEncoding>
constexpr width_t str_width
    ( CharEncoding encoding
    , width_t limit
    , const underlying_char_type<CharEncoding::char_size>* 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 underlying_char_type<CharEncoding::char_size>* 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

6.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
        , underlying_char_type<CharEncoding::char_size> ) const;

    template <typename CharEncoding>
    width_t str_width
        ( CharEncoding encoding
        , width_t limit
        , const underlying_char_type<CharEncoding::char_size>* 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 underlying_char_type<CharEncoding::char_size>* str
        , std::size_t str_len
        , surrogate_policy ) const;

private:

    const CharWidthFunc func_; // exposition only
};

6.5.1. 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.

6.5.2. Member functions

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

func_(encoding.decode_char(ch))

template <typename CharEncoding>
constexpr width_t str_width
    ( CharEncoding encoding
    , width_t limit
    , const underlying_char_type<CharEncoding::char_size>* 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 underlying_outbuff<4> — 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 underlying_char_type<CharEncoding::char_size>* 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 underlying_outbuff<4>.

  • 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.

6.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}

6.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

6.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);

7. Numeric punctuation

To-do

8. Miscellaneous

8.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

8.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

8.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

8.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))

8.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));

8.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.

8.7. Format function aliases

namespace strf {
inline namespace format_functions {

template <typename T>
constexpr auto hex(const T& value)
{
    return fmt(value).hex();
}

template <typename T>
constexpr auto dec(const T& value)
{
    return fmt(value).dec();
}

template <typename T>
constexpr auto oct(const T& value)
{
    return fmt(value).oct();
}

template <typename T>
constexpr auto bin(const T& value)
{
    return fmt(value).bin();
}

template <typename T>
constexpr auto left(const T& value, int width)
{
    return fmt(value) < width;
}

template <typename T>
constexpr auto right(const T& value, int width)
{
    return fmt(value) > width;
}

template <typename T>
constexpr auto split(const T& value, int width)
{
    return fmt(value) % width;
}

template <typename T>
constexpr auto center(const T& value, int width)
{
    return fmt(value) ^ width;
}

template <typename T>
constexpr auto left(const T& value, int width, char32_t fill)
{
    return fmt(value).fill(fill) < width;
}

template <typename T>
constexpr auto right(const T& value, int width, char32_t fill)
{
    return fmt(value).fill(fill) > width;
}

template <typename T>
constexpr auto conv(const T& value)
{
    return fmt(value).conv();
}

template <typename T, typename CharEncoding>
constexpr auto conv(const T& value, const CharEncoding& cs)
{
    return fmt(value).conv(cs);
}

template <typename T>
constexpr auto sani(const T& value)
{
    return fmt(value).sani();
}

template <typename T, typename CharEncoding>
constexpr auto sani(const T& value, const CharEncoding& cs)
{
    return fmt(value).sani(cs);
}

} // inline namespace format_functions
} // namespace strf