NAV Navbar
  • Introduction
  • APIDocs
  • Internal
  • Introduction

    ThorsNisse

    Description

    This utility is designed to mimic the string format arguments used by the C function printf(). A Format object takes a "format string" that specify a printable string with conversion specifications introduced by the '%' character. For each conversion specifications there must also be a matching argument of the correct type.

    If there are not enough arguments or they are the wrong type this is a runtime error as the format string is parsed at runtime during the construction of the Format object.

    When the format object is passed to a std::iostream using the serialization operator operator<< all the arguments are serialized to the stream according to the conversion specifications.

    Create Format

    #include "ThorsIOUtil/Format.h"
    #include <iostream>
    
    using namespace Fmt = ThorsAnvil::IOUtil;
    
    int main()
    {
        std::cout << Fmt::make_format("Print Integre >%5.3d<\n", 5);   // Print Integre >  005<
    }

    So how do you build a Format object?

    The easiest way is to use the make_format(<format string> [, argument]*). This function takes the format string and the arguments and creates a Format object using the types of the arguments to construct a Format object of the correct type. Note this can be done by hand, but like std::pair<> it is simpler to use the utility function.

    Testing

    This library is tested with the same unit tests used by the GNU libraries to test printf().

    Conversion Specifications

    Format

    The conversion specifiers have the following format.

    Only the <Specifier> is required, all other part of the conversion specifiers are optional.

    Specifier

    Specifier
        %           %% generates '%'
    
        // The following match integer values.
        //      will match an int parameter unless modified by the `Length`
        d           prints a signed integer base 10
        i           prints a signed integer base 10
        o           prints an unsigned integer base 8
        u           prints an unsigned integer base 10
        X/x         prints an unsigned integer base 16
    
        // The following matches floating point values
        //      will match a double value unless modified by the `Length`
        f           prints using a fixed point notation:                -?ddd.ddd
        E/e         prints using expontent notation                     -?d.ddd[Ee][+-]?dd
        G/g         prints using fixed point or exponent notation.
        A/a         prints using a hexidecimal fraction notation.       -?0xh.hhh[Pp][+-]?dd
    
        // Charavter types
        //      Can use the `Length` modifier to change what it matches.
        c           matches a char input                prints an unsigned char
        s           matches a char* or std::string      prints a string of characters
    
        // Other conversions
        p           matches any pointer                 prints a hex number prefixed with 0x
        n           does not match anything             prints the number of characters printed

    The specifier field basically describes what type of object is being serialized. There are basically four types of object:

    There are two special cases:

    Example: %d

    Flag

    Flags:  one or more of:
        // For integers, floating point, char, string and pointer values
        -           Left justify output inside the field.
                    This assumes you specify a `<Width>` field otherwise this will have no affect
    
        // For integers and floating point values
        +           Print the '+' symbol for positive values.
        <Space>     Print the ' ' symbol for positive values (ignored if + also used)
                    This helps positive and negative values align with forcing the '+' symbol
        '           Seporate digits into groups specified by LC_NUMERIC
        0           Pad number with zero rather than space. Padding comes after sign and base information.
                    It is used to make sure the serialized output is at least `<Width>` wide.
                    Ignored if the '-' flag is used.
    
        // For integers values
        #           Add base information to number (After sign)
                    For %o values prefix value with '0'
                    For %x values prefix value with '0x'
                    For %X values prefix value with '0X'
        // For floating point values
        #           Allways add a decimal point
                    For %g %G forces trailing zero after decimal point.

    The flag field is optional. If used you can use one or more of the flag characters to control how the value is serialized.

    Example: %#x

    Width

    The width is an optional integer that specifies the minimum width of the field we use to print the value. If the value is smaller than the width the field is padded using the padding value (see Flags to change the padding value).

    Note: If the value is larger than the specified width it will overflow the field (i.e. no cutting is done to truncate the value to the field width).

    Example: %15d

    Precision

    Precision:
        // For integers values
            The minimum number of digits used in the number.
            Leadding zero(s) are added to achieve the minumum precision required.
            If no value given then print as many digits as required.
            If precision is zero and the value is zero then no value is printed.
    
        // For floating point values
            The precision is the number of digits following the decimal point

    An optional field. A number prefixed by the '.' character. For integer and floating point values defines the number of digits that will be used.

    Example: %.8f

    Length

    Length: 
        // The specifiers d/i/o/u/x/X match integer values.
        // Unless proceeeded by one of the following length specifiers.
        // That allow us match against alternatives object types.
        hh          matches a char      or  unsigned char           parameter
        h           marches a short     or  unsigned short          parameter
        l           matches a long      or  unsigned long           parameter
        ll          matches a long long or  unsigned long long      parameter
        L           matches a long long or  unsigned long long      parameter
        q           matches a long long or  unsigned long long      parameter
        j           matches a std::intmax_t                         parameter
        t           matches a std::ptrdiff_t                        parameter
        z           matches a std::size_t                           parameter
    
        // The following match floating point values unless modified by the Length parameter
        L           matches a long double                           parameter
    
        // The following match char and string conversions.
        //      rather than `char` the base of the char/string will be std::wchar_t

    The <Length> specifier changes the type of value that is bound to the specifier.

    Example: %ld

    Notes

    #include "ThorsIOUtil/Format.h"
    #include <iostream>
    
    using namespace Fmt = ThorsAnvil::IOUtil;
    
    int main()
    {
        short shortValue = 10;
        std::cout << Fmt::make_format("Print short >%hd<\n", shortValue);
        std::cout << Fmt::make_cppformat("Print short >%hd<\n", shortValue);
    
        int intValue = 10;
        std::cout << Fmt::make_format("Print short >%hd<\n", intValue);
        std::cout << Fmt::make_cppformat("Print short >%hd<\n", intValue);  // This will throw a runtime error.
    }

    In C char and short values are converted to int before being passed as arguments to printf(). Thus the <Length> fields hh and h will convert the int back to the appropriate type (char, short) before printf() serializes the value. This has the side affect that you can pass int values to printf() and it will serialize correctly.

    To conform with C we also allow int values to bind to %hd and %hhd conversion specifiers by default. But we also provide a stricter interpretation for C++ users that only allows char to bind to %hhd values and short to bind to %hd values.

    If you use make_format() the formatter uses C compatibility mode and will match %hhd and %hd against int values in addition to the match type expected.

    If you use make_cppformat() the conversion specifiers use the stricter C++ type mode.

    APIDocs

    NameSpace:
    ThorsAnvil::IOUtil
    Headers:
    ThorsIOUtil
    Format.h
    • Format<Args...> make_format()
    • Format<Args...> make_cppformat()

    make_format

    Header:
    ThorsIOUtil/Format.h
    NameSpace:
    ThorsAnvil::IOUtil
    Template:
    template<typename... Args>
    Return Value: char const* fmt
    A format object that keeps a const reference to each argument.
    Parameters
     
    char const* fmt
    The format string.
     
    Args const&... args
    Template parameter pack. Each argument is matched to a conversion specifier.

    Builds a Format object based on the types of the arguments.

    make_cppformat

    Header:
    ThorsIOUtil/Format.h
    NameSpace:
    ThorsAnvil::IOUtil
    Template:
    template<typename... Args>
    Return Value: char const* fmt
    A format object that keeps a const reference to each argument.
    Parameters
     
    char const* fmt
    The format string.
     
    Args const&... args
    Template parameter pack. Each argument is matched to a conversion specifier.

    Builds a Format object based on the types of the arguments.

    This version has slightly tighter restrictions on matching parameters to conversion specifiers.
    Like C++ the type system is much pickier than C.

    Internal

    NameSpace:
    ThorsAnvil::IOUtil
    Headers:
    ThorsIOUtil
    Format.h
    • Format
    FormatInfo.h
    • FormatInfo
    Formatter.h
    • NormalizeChar
    • Formatter
    SignConversionOption.h
    • SignConversionOption
    • SignConversionOption<char>
    • SignConversionOption<short>
    • SignConversionOption<int>
    • SignConversionOption<long>
    • SignConversionOption<long long>
    • SignConversionOption<unsigned char>
    • SignConversionOption<unsigned short>
    • SignConversionOption<unsigned int>
    • SignConversionOption<unsigned long>
    • SignConversionOption<unsigned long long>
    printIntToStream.h
    • void printIntToStream()
    printStringToStream.h
    • void printStringToStream()
    printToStream.h
    • CharIntConverter
    • CharIntConverter<char>
    • CharIntConverter<unsigned char>
    • void printToStream()
    • void printToStream()
    • void printToStream()
    saveToStream.h
    • void saveToStream()
    • void saveToStream()

    Format

    Header:
    ThorsIOUtil/Format.h
    NameSpace:
    ThorsAnvil::IOUtil
    Template:
    template<typename... Args>
    Class:
    Format

    This is the object returned by make_format() and make_cppformat()
    This is the object that is passed to the std::ostream via operator<<.

    Internally it keeps the original string and references to all the parameters that
    need to be serialized. When the object is constructed (at runtime) the conversion
    specifiers in the string are validated against the actual parameters to make sure
    the correctly match.

    FormatInfo

    Header:
    ThorsIOUtil/FormatInfo.h
    NameSpace:
    ThorsAnvil::IOUtil
    Class:
    FormatInfo

    Each conversion specifier in the format string is parsed and converted into an object of this type.

    NormalizeChar

    Header:
    ThorsIOUtil/Formatter.h
    NameSpace:
    ThorsAnvil::IOUtil
    Template:
    template<typename T>
    Class:
    NormalizeChar

    Char is a very special class.

    The type char can be either signed char or unsigned char and is its own specif type (unlike int).
    type for all classes except signed char which is converted to char.

    Formatter

    Header:
    ThorsIOUtil/Formatter.h
    NameSpace:
    ThorsAnvil::IOUtil
    Template:
    template<>
    Class:
    Formatter

    Parses a string segment.

    It saves the static prefix before a conversion specifier.
    Then it saves a conversion specifier into the info member.
    It keeps track of the number of characters parsed in used.

    SignConversionOption

    Header:
    ThorsIOUtil/SignConversionOption.h
    NameSpace:
    ThorsAnvil::IOUtil
    Template:
    template<typename T>
    Class:
    SignConversionOption

    When handling integer types some
    automatic conversions are allowed.

    This type handles these conversions.
    It is used by Formatter::apply()

    SignConversionOption<char>

    Header:
    ThorsIOUtil/SignConversionOption.h
    NameSpace:
    ThorsAnvil::IOUtil
    Template:
    template<>
    Class:
    SignConversionOption<char>

    Specialization of SignConversionOption

    SignConversionOption<short>

    Header:
    ThorsIOUtil/SignConversionOption.h
    NameSpace:
    ThorsAnvil::IOUtil
    Template:
    template<>
    Class:
    SignConversionOption<short>

    Specialization of SignConversionOption

    SignConversionOption<int>

    Header:
    ThorsIOUtil/SignConversionOption.h
    NameSpace:
    ThorsAnvil::IOUtil
    Template:
    template<>
    Class:
    SignConversionOption<int>

    Specialization of SignConversionOption

    SignConversionOption<long>

    Header:
    ThorsIOUtil/SignConversionOption.h
    NameSpace:
    ThorsAnvil::IOUtil
    Template:
    template<>
    Class:
    SignConversionOption<long>

    Specialization of SignConversionOption

    SignConversionOption<long long>

    Header:
    ThorsIOUtil/SignConversionOption.h
    NameSpace:
    ThorsAnvil::IOUtil
    Template:
    template<>
    Class:
    SignConversionOption<long long>

    Specialization of SignConversionOption

    SignConversionOption<unsigned char>

    Header:
    ThorsIOUtil/SignConversionOption.h
    NameSpace:
    ThorsAnvil::IOUtil
    Template:
    template<>
    Class:
    SignConversionOption<unsigned char>

    Specialization of SignConversionOption

    SignConversionOption<unsigned short>

    Header:
    ThorsIOUtil/SignConversionOption.h
    NameSpace:
    ThorsAnvil::IOUtil
    Template:
    template<>
    Class:
    SignConversionOption<unsigned short>

    Specialization of SignConversionOption

    SignConversionOption<unsigned int>

    Header:
    ThorsIOUtil/SignConversionOption.h
    NameSpace:
    ThorsAnvil::IOUtil
    Template:
    template<>
    Class:
    SignConversionOption<unsigned int>

    Specialization of SignConversionOption

    SignConversionOption<unsigned long>

    Header:
    ThorsIOUtil/SignConversionOption.h
    NameSpace:
    ThorsAnvil::IOUtil
    Template:
    template<>
    Class:
    SignConversionOption<unsigned long>

    Must have some description

    SignConversionOption<unsigned long long>

    Header:
    ThorsIOUtil/SignConversionOption.h
    NameSpace:
    ThorsAnvil::IOUtil
    Template:
    template<>
    Class:
    SignConversionOption<unsigned long long>

    Must have some description

    printIntToStream

    Header:
    ThorsIOUtil/printIntToStream.h
    NameSpace:
    ThorsAnvil::IOUtil
    Template:
    template<typename T>
    Return Value: std::ostream& s
    Parameters
     
    std::ostream& s
    stream to serialize onto the integer argument we want to serialize formatInfo object that defines how to serialize arg
     
    T arg
    the integer argument we want to serialize formatInfo object that defines how to serialize arg
     
    FormatInfo const& info
    formatInfo object that defines how to serialize arg

    Given an argument arg (which is one of the int types) and a format info serialize it to the stream s

    printStringToStream

    Header:
    ThorsIOUtil/printStringToStream.h
    NameSpace:
    ThorsAnvil::IOUtil
    Return Value: std::ostream& s
    Parameters
     
    std::ostream& s
    stream to serialize onto the string argument we want to serialize formatInfo object that defines how to serialize arg
     
    char const* const& arg
    the string argument we want to serialize formatInfo object that defines how to serialize arg
     
    FormatInfo const& info
    formatInfo object that defines how to serialize arg

    Given an argument arg and a format info serialize it to the stream s

    printToStream

    Header:
    ThorsIOUtil/printToStream.h
    NameSpace:
    ThorsAnvil::IOUtil
    Template:
    template<typename T>
    Return Value: std::ostream& s
    Parameters
     
    std::ostream& s
     
    char const* const& arg
     
    FormatInfo const& info

    Template method for strings

    printToStream

    Header:
    ThorsIOUtil/printToStream.h
    NameSpace:
    ThorsAnvil::IOUtil
    Template:
    template<typename T>
    Return Value: std::ostream& s
    Parameters
     
    std::ostream& s
     
    char const* const& arg
     
    FormatInfo const& info

    Template method for strings

    printToStream

    Header:
    ThorsIOUtil/printToStream.h
    NameSpace:
    ThorsAnvil::IOUtil
    Template:
    template<typename T>
    Return Value: std::ostream& s
    Parameters
     
    std::ostream& s
     
    char const* const& arg
     
    FormatInfo const& info

    Template method for strings

    CharIntConverter

    Header:
    ThorsIOUtil/printToStream.h
    NameSpace:
    ThorsAnvil::IOUtil
    Template:
    template<typename T>
    Class:
    CharIntConverter

    CharIntConverter<char>

    Header:
    ThorsIOUtil/printToStream.h
    NameSpace:
    ThorsAnvil::IOUtil
    Template:
    template<>
    Class:
    CharIntConverter<char>

    CharIntConverter<unsigned char>

    Header:
    ThorsIOUtil/printToStream.h
    NameSpace:
    ThorsAnvil::IOUtil
    Template:
    template<>
    Class:
    CharIntConverter<unsigned char>

    saveToStream

    Header:
    ThorsIOUtil/saveToStream.h
    NameSpace:
    ThorsAnvil::IOUtil
    Template:
    template<typename T>
    Return Value: std::ostream&
    Parameters
     
    std::ostream&
     
    Dynamic
     
    T const&

    saveToStream

    Header:
    ThorsIOUtil/saveToStream.h
    NameSpace:
    ThorsAnvil::IOUtil
    Template:
    template<typename T>
    Return Value: std::ostream&
    Parameters
     
    std::ostream&
     
    Dynamic
     
    T const&