jaulib v1.4.1-17-gd77ace3-dirty
Jau Support Library (C++, Java, ..)
Loading...
Searching...
No Matches
jau::cfmt Namespace Reference

Author: Sven Gothel sgoth.nosp@m.el@j.nosp@m.ausof.nosp@m.t.co.nosp@m.m Copyright (c) 2021-2026 Gothel Software e.K. More...

Namespaces

namespace  impl
 

Classes

struct  FormatOpts
 
class  Result
 

Enumerations

enum class  cspec_t : uint16_t {
  cspec_t::none , cspec_t::character , cspec_t::string , cspec_t::pointer ,
  cspec_t::signed_int , cspec_t::unsigned_int , cspec_t::floating_point , cspec_t::exp_float ,
  cspec_t::alt_float , cspec_t::hex_float
}
 Format conversion specifier (fully defined w/ radix) More...
 
enum class  flags_t : uint16_t {
  flags_t::none = 0 , flags_t::hash = (uint16_t)1 << 1 , flags_t::zeropad = (uint16_t)1 << 2 , flags_t::left = (uint16_t)1 << 3 ,
  flags_t::space = (uint16_t)1 << 4 , flags_t::plus = (uint16_t)1 << 5 , flags_t::thousands = (uint16_t)1 << 6 , flags_t::uppercase = (uint16_t)1 << 8
}
 Format flags. More...
 
enum class  plength_t : uint16_t {
  plength_t::none , plength_t::hh , plength_t::h , plength_t::l ,
  plength_t::ll , plength_t::L , plength_t::j , plength_t::z ,
  plength_t::t
}
 Format length modifiers. More...
 
enum class  pstate_t : uint16_t {
  pstate_t::error , pstate_t::outside , pstate_t::start , pstate_t::field_width ,
  pstate_t::precision
}
 

Functions

template<typename... Targs>
consteval_cxx20 ssize_t check (std::string_view fmt, const Targs &...) noexcept
 Strict compile-time type validation of deduced argument-types against the format string.
 
template<typename... Targs>
consteval_cxx20 ssize_t check2 (std::string_view fmt) noexcept
 Strict compile-time type validation of explicit argument-types against the format string.
 
template<typename... Targs>
consteval_cxx20 int check2Line (std::string_view fmt) noexcept
 Strict compile-time type validation of explicit argument-types against the format string.
 
template<typename... Targs>
consteval_cxx20 int checkLine (std::string_view fmt, const Targs &...) noexcept
 Strict compile-time type validation of deduced argument-types against the format string.
 
template<typename... Targs>
consteval_cxx20 Result checkR (std::string_view fmt, const Targs &...) noexcept
 Strict compile-time type validation of deduced argument-types against the format string.
 
template<typename... Targs>
consteval_cxx20 Result checkR2 (std::string_view format) noexcept
 Strict compile-time type validation of explicit argument-types against the format string.
 
template<typename... Targs>
std::string format (size_t maxLen, std::string_view fmt, const Targs &...args) noexcept
 Strict format with type validation of arguments against the format string.
 
template<typename... Targs>
std::string format (std::string_view fmt, const Targs &...args) noexcept
 Strict format with type validation of arguments against the format string.
 
template<typename... Targs>
Result formatR (const std::size_t strLenHint, std::string &s, size_t maxLen, std::string_view fmt, const Targs &...args) noexcept
 Strict format with type validation of arguments against the format string, appending to the given destination.
 
template<typename... Targs>
Result formatR (const std::size_t strLenHint, std::string &s, std::string_view fmt, const Targs &...args) noexcept
 Strict format with type validation of arguments against the format string, appending to the given destination.
 
template<typename... Targs>
Result formatR (std::string &s, size_t maxLen, std::string_view fmt, const Targs &...args) noexcept
 Strict format with type validation of arguments against the format string, appending to the given destination.
 
template<typename... Targs>
Result formatR (std::string &s, std::string_view fmt, const Targs &...args) noexcept
 Strict format with type validation of arguments against the format string, appending to the given destination.
 
 JAU_MAKE_BITFIELD_ENUM_STRING (flags_t, hash, zeropad, left, space, plus, thousands, uppercase)
 
 JAU_MAKE_ENUM_STRING (cspec_t, character, string, pointer, signed_int, unsigned_int, floating_point, exp_float, alt_float, hex_float)
 
 JAU_MAKE_ENUM_STRING (plength_t, hh, h, l, ll, L, j, z, t)
 
std::ostream & operator<< (std::ostream &out, const FormatOpts &o)
 
std::ostream & operator<< (std::ostream &out, const Result &pc)
 
static constexpr const char * to_string (pstate_t s) noexcept
 

Variables

constexpr const size_t default_string_capacity = 511
 Default string reserved capacity w/o EOS (511)
 
constexpr const size_t num_max_slen = 31
 Maximum net number string len w/o EOS, up to uint64_t.
 

Detailed Description

Author: Sven Gothel sgoth.nosp@m.el@j.nosp@m.ausof.nosp@m.t.co.nosp@m.m Copyright (c) 2021-2026 Gothel Software e.K.


SPDX-License-Identifier: MIT

This Source Code Form is subject to the terms of the MIT License If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/license/mit/.

jau::cfmt, a snprintf compliant runtime string format and compile-time validator

Features

  • Compile type validation of arguments against the format string
    • Possible via consteval capable constexpr implementation
    • Live response via static_assert expressions within your IDE
    • Example using jau_string_check(fmt, ...) macro utilizing jau::cfmt::check2 The macro resolves the passed arguments types via decltype to be utilized for jau::cfmt::check2
      jau_string_check("Hello %s %u", "World", 2.0); // shows static_assert() argument error for argument 2 (float, not unsigned integral)
      jau_string_checkLine("Hello %s %u", "World", 2.0); // shows static_assert() source-line error for argument 2 (float, not unsigned integral)
      #define jau_string_check(fmt,...)
      Macro produces compile time validation using a static_assert against jau::cfmt::check2.
      #define jau_string_checkLine(fmt,...)
      Macro produces compile time validation using a static_assert against jau::cfmt::check2Line.
  • Runtime safe string formatting via jau::format_string
    std::string s0 = "World";
    std::string s1 = jau::format_string("Hello %s, %d + %d = %'d", s0, 1, 1, 2000);
    std::string s3 = jau::format_string_h(100, "Hello %s, %d + %d = %'d", s0, 1, 1, 2000); // using a string w/ reserved size of 100
    // string concatenation, each `formatR` appends to the given referenced string
    std::string concat;
    concat.reserve(1000);
    jau::cfmt::formatR(concat, "Hello %s, %d + %d = %'d", s0, 1, 1, 2000);
    ...
    jau::cfmt::formatR(concat, "%#b", 2U);
    Result formatR(std::string &s, size_t maxLen, std::string_view fmt, const Targs &...args) noexcept
    Strict format with type validation of arguments against the format string, appending to the given des...
    std::string format_string(std::string_view fmt, const Args &...args) noexcept
    Safely returns a (non-truncated) string according to snprintf() formatting rules using a reserved str...
    std::string format_string_h(const std::size_t strLenHint, std::string_view fmt, const Args &...args) noexcept
    Safely returns a (non-truncated) string according to snprintf() formatting rules and variable number ...
  • Both, compile time check and runtime formatting via jau_format_string macro (the actual goal)
    std::string s1 = jau_format_string("Hello %s, %d + %d = %'d", s0, 1, 1, 2000);
    std::string s2 = jau_format_string_h(100, "Hello %s, %d + %d = %'d", s0, 1, 1, 2000); // using a string w/ reserved size of 100
    #define jau_format_string_h(strLenHint, fmt,...)
    Macro, safely returns a (non-truncated) string according to snprintf() formatting rules and variable ...
    #define jau_format_string(fmt,...)
    Macro, safely returns a (non-truncated) string according to snprintf() formatting rules using a reser...
  • Compatible with fprintf, snprintf, etc

Type Conversion

Implementation follows type conversion rules as described in Variadic Default Conversion

  • float to double promotion
  • bool, char, short, and unscoped enumerations are converted to int or wider integer types, see also va_arg
  • void pointer tolerance
  • Exception signedness conversion
    • Allows positive signed to unsigned type conversion
      • Positive check at runtime only
    • Allows unsigned to signed type conversion if sizeof(unsigned type) < sizeof(signed type)
      • Compile time check
    • Otherwise fails intentionally

Implementation Details

General

  • Validates argument types against format string at compile time (consteval)
  • Formats resulting string using argument values against format string at runtime
  • Written in C++20 using template argument pack w/ save argument type checks
  • Type erasure to wider common denominator, i.e. uint64, const char* const, std::string_view, reducing code footprint

Behavior

  • nullptr conversion value similar to glibc
    • string produces (null)
    • pointer produces (nil)
  • Safe Signedness Conversion
    • Not accepting unsigned -> signed conversion if sizeof(unsigned type) >= sizeof(signed type) to avoid overflow (compile time check), otherwise OK
    • Not accepting negative integral value for unsigned (runtime check)
  • Accept given type <= integral target type, conversion to wider types
  • Accept enum types for integer conversion.
    • Only if underlying type is unsigned, it can't be used for signed integer conversion (see above)
  • Accept direct std::string and std::string_view for s string arguments
  • Arithmetic integral + floating point types are limited to a maximum of 64-bit
  • Runtime Errors
    • Failed runtime checks will inject an error market, e.g. <E#1@1234:Cnv> where the 1st argument caused a conversion error (Cnv) as detected in string_cfmt.hpp like 1234.
    • Argument 0 indicated an error in the format string.
    • Len tags a length modifier error
    • Cnv tags a conversion error

Supported Format String

%[flags][width][.precision][length modifier]conversion

Flags

The following flags are supported

  • #: hash, C99. Adds leading prefix for radix != 10.
  • 0: zeropad, C99
  • -: left, C99
  •  : space, C99
  • +: plus, C99
  • ': thousands, POSIX
  • ,: thousands, OpenJDK (alias for Java users)

Width and Precision

Width and precision also supports * to use the next argument for its value.

However, *m$ (decimal integer m) for the m-th argument is not yet supported.

Length Modifiers

The following length modifiers are supported

  • hh [unsigned] char, ignored for floating point
  • h [unsigned] short, ignored for floating point
  • l [unsigned] long, ignored for floating point
  • ll [unsigned] long long
  • q deprecated synonym for ll
  • L long double
  • j uintmax_t or intmax_t
  • z size_t or ssize_t
  • Z deprecated synonym for z
  • t ptrdiff_t

Conversion Specifiers

The following standard conversion specifiers are supported:

  • Basic
    • c character
    • s string
    • p pointer
    • d signed integral or i
  • Unsigned integral
    • o octal unsigned
    • x X hexadecimal unsigned low and capital chars
    • b binary unsigned presentation (extension)
    • u decimal unsigned
  • Floating point
    • f or F double floating point
    • e, E exponential low- and capital E
    • g, G alternate exponential low- and capital E
    • a, A hexadecimal low- and capital chars
  • Aliases
    • i -> d
    • F -> f

Extended Conversion Specifier

  • b bitpattern of unsigned integral w/ prefix 0b (if # flag is added)

Special Thanks

To the project A printf / sprintf Implementation for Embedded Systems worked on by Marco Paland and many others. I have used their test_suite.cpp code within our unit test test_stringfmt_format.cpp and also utilized their floating point parsing within append_float and append_efloat.

Further Documentation