diff options
Diffstat (limited to 'lib/spdlog/fmt/bundled/printf.h')
| -rw-r--r-- | lib/spdlog/fmt/bundled/printf.h | 723 | 
1 files changed, 723 insertions, 0 deletions
diff --git a/lib/spdlog/fmt/bundled/printf.h b/lib/spdlog/fmt/bundled/printf.h new file mode 100644 index 0000000..679e8fc --- /dev/null +++ b/lib/spdlog/fmt/bundled/printf.h @@ -0,0 +1,723 @@ +/* + Formatting library for C++ + + Copyright (c) 2012 - 2016, Victor Zverovich + All rights reserved. + + For the license information refer to format.h. + */ + +#ifndef FMT_PRINTF_H_ +#define FMT_PRINTF_H_ + +#include <algorithm> // std::fill_n +#include <limits>    // std::numeric_limits + +#include "ostream.h" + +namespace fmt { +namespace internal { + +// Checks if a value fits in int - used to avoid warnings about comparing +// signed and unsigned integers. +template<bool IsSigned> +struct IntChecker +{ +    template<typename T> +    static bool fits_in_int(T value) +    { +        unsigned max = std::numeric_limits<int>::max(); +        return value <= max; +    } +    static bool fits_in_int(bool) +    { +        return true; +    } +}; + +template<> +struct IntChecker<true> +{ +    template<typename T> +    static bool fits_in_int(T value) +    { +        return value >= std::numeric_limits<int>::min() && value <= std::numeric_limits<int>::max(); +    } +    static bool fits_in_int(int) +    { +        return true; +    } +}; + +class PrecisionHandler : public ArgVisitor<PrecisionHandler, int> +{ +public: +    void report_unhandled_arg() +    { +        FMT_THROW(FormatError("precision is not integer")); +    } + +    template<typename T> +    int visit_any_int(T value) +    { +        if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value)) +            FMT_THROW(FormatError("number is too big")); +        return static_cast<int>(value); +    } +}; + +// IsZeroInt::visit(arg) returns true iff arg is a zero integer. +class IsZeroInt : public ArgVisitor<IsZeroInt, bool> +{ +public: +    template<typename T> +    bool visit_any_int(T value) +    { +        return value == 0; +    } +}; + +// returns the default type for format specific "%s" +class DefaultType : public ArgVisitor<DefaultType, char> +{ +public: +    char visit_char(int) +    { +        return 'c'; +    } + +    char visit_bool(bool) +    { +        return 's'; +    } + +    char visit_pointer(const void *) +    { +        return 'p'; +    } + +    template<typename T> +    char visit_any_int(T) +    { +        return 'd'; +    } + +    template<typename T> +    char visit_any_double(T) +    { +        return 'g'; +    } + +    char visit_unhandled_arg() +    { +        return 's'; +    } +}; + +template<typename T, typename U> +struct is_same +{ +    enum +    { +        value = 0 +    }; +}; + +template<typename T> +struct is_same<T, T> +{ +    enum +    { +        value = 1 +    }; +}; + +// An argument visitor that converts an integer argument to T for printf, +// if T is an integral type. If T is void, the argument is converted to +// corresponding signed or unsigned type depending on the type specifier: +// 'd' and 'i' - signed, other - unsigned) +template<typename T = void> +class ArgConverter : public ArgVisitor<ArgConverter<T>, void> +{ +private: +    internal::Arg &arg_; +    wchar_t type_; + +    FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter); + +public: +    ArgConverter(internal::Arg &arg, wchar_t type) +        : arg_(arg) +        , type_(type) +    { +    } + +    void visit_bool(bool value) +    { +        if (type_ != 's') +            visit_any_int(value); +    } + +    void visit_char(int value) +    { +        if (type_ != 's') +            visit_any_int(value); +    } + +    template<typename U> +    void visit_any_int(U value) +    { +        bool is_signed = type_ == 'd' || type_ == 'i'; +        if (type_ == 's') +        { +            is_signed = std::numeric_limits<U>::is_signed; +        } + +        using internal::Arg; +        typedef typename internal::Conditional<is_same<T, void>::value, U, T>::type TargetType; +        if (const_check(sizeof(TargetType) <= sizeof(int))) +        { +            // Extra casts are used to silence warnings. +            if (is_signed) +            { +                arg_.type = Arg::INT; +                arg_.int_value = static_cast<int>(static_cast<TargetType>(value)); +            } +            else +            { +                arg_.type = Arg::UINT; +                typedef typename internal::MakeUnsigned<TargetType>::Type Unsigned; +                arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value)); +            } +        } +        else +        { +            if (is_signed) +            { +                arg_.type = Arg::LONG_LONG; +                // glibc's printf doesn't sign extend arguments of smaller types: +                //   std::printf("%lld", -42);  // prints "4294967254" +                // but we don't have to do the same because it's a UB. +                arg_.long_long_value = static_cast<LongLong>(value); +            } +            else +            { +                arg_.type = Arg::ULONG_LONG; +                arg_.ulong_long_value = static_cast<typename internal::MakeUnsigned<U>::Type>(value); +            } +        } +    } +}; + +// Converts an integer argument to char for printf. +class CharConverter : public ArgVisitor<CharConverter, void> +{ +private: +    internal::Arg &arg_; + +    FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); + +public: +    explicit CharConverter(internal::Arg &arg) +        : arg_(arg) +    { +    } + +    template<typename T> +    void visit_any_int(T value) +    { +        arg_.type = internal::Arg::CHAR; +        arg_.int_value = static_cast<char>(value); +    } +}; + +// Checks if an argument is a valid printf width specifier and sets +// left alignment if it is negative. +class WidthHandler : public ArgVisitor<WidthHandler, unsigned> +{ +private: +    FormatSpec &spec_; + +    FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler); + +public: +    explicit WidthHandler(FormatSpec &spec) +        : spec_(spec) +    { +    } + +    void report_unhandled_arg() +    { +        FMT_THROW(FormatError("width is not integer")); +    } + +    template<typename T> +    unsigned visit_any_int(T value) +    { +        typedef typename internal::IntTraits<T>::MainType UnsignedType; +        UnsignedType width = static_cast<UnsignedType>(value); +        if (internal::is_negative(value)) +        { +            spec_.align_ = ALIGN_LEFT; +            width = 0 - width; +        } +        unsigned int_max = std::numeric_limits<int>::max(); +        if (width > int_max) +            FMT_THROW(FormatError("number is too big")); +        return static_cast<unsigned>(width); +    } +}; +} // namespace internal + +/** +  \rst +  A ``printf`` argument formatter based on the `curiously recurring template +  pattern <http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern>`_. + +  To use `~fmt::BasicPrintfArgFormatter` define a subclass that implements some +  or all of the visit methods with the same signatures as the methods in +  `~fmt::ArgVisitor`, for example, `~fmt::ArgVisitor::visit_int()`. +  Pass the subclass as the *Impl* template parameter. When a formatting +  function processes an argument, it will dispatch to a visit method +  specific to the argument type. For example, if the argument type is +  ``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass +  will be called. If the subclass doesn't contain a method with this signature, +  then a corresponding method of `~fmt::BasicPrintfArgFormatter` or its +  superclass will be called. +  \endrst + */ +template<typename Impl, typename Char, typename Spec> +class BasicPrintfArgFormatter : public internal::ArgFormatterBase<Impl, Char, Spec> +{ +private: +    void write_null_pointer() +    { +        this->spec().type_ = 0; +        this->write("(nil)"); +    } + +    typedef internal::ArgFormatterBase<Impl, Char, Spec> Base; + +public: +    /** +      \rst +      Constructs an argument formatter object. +      *writer* is a reference to the output writer and *spec* contains format +      specifier information for standard argument types. +      \endrst +     */ +    BasicPrintfArgFormatter(BasicWriter<Char> &w, Spec &s) +        : internal::ArgFormatterBase<Impl, Char, Spec>(w, s) +    { +    } + +    /** Formats an argument of type ``bool``. */ +    void visit_bool(bool value) +    { +        Spec &fmt_spec = this->spec(); +        if (fmt_spec.type_ != 's') +            return this->visit_any_int(value); +        fmt_spec.type_ = 0; +        this->write(value); +    } + +    /** Formats a character. */ +    void visit_char(int value) +    { +        const Spec &fmt_spec = this->spec(); +        BasicWriter<Char> &w = this->writer(); +        if (fmt_spec.type_ && fmt_spec.type_ != 'c') +            w.write_int(value, fmt_spec); +        typedef typename BasicWriter<Char>::CharPtr CharPtr; +        CharPtr out = CharPtr(); +        if (fmt_spec.width_ > 1) +        { +            Char fill = ' '; +            out = w.grow_buffer(fmt_spec.width_); +            if (fmt_spec.align_ != ALIGN_LEFT) +            { +                std::fill_n(out, fmt_spec.width_ - 1, fill); +                out += fmt_spec.width_ - 1; +            } +            else +            { +                std::fill_n(out + 1, fmt_spec.width_ - 1, fill); +            } +        } +        else +        { +            out = w.grow_buffer(1); +        } +        *out = static_cast<Char>(value); +    } + +    /** Formats a null-terminated C string. */ +    void visit_cstring(const char *value) +    { +        if (value) +            Base::visit_cstring(value); +        else if (this->spec().type_ == 'p') +            write_null_pointer(); +        else +            this->write("(null)"); +    } + +    /** Formats a pointer. */ +    void visit_pointer(const void *value) +    { +        if (value) +            return Base::visit_pointer(value); +        this->spec().type_ = 0; +        write_null_pointer(); +    } + +    /** Formats an argument of a custom (user-defined) type. */ +    void visit_custom(internal::Arg::CustomValue c) +    { +        BasicFormatter<Char> formatter(ArgList(), this->writer()); +        const Char format_str[] = {'}', 0}; +        const Char *format = format_str; +        c.format(&formatter, c.value, &format); +    } +}; + +/** The default printf argument formatter. */ +template<typename Char> +class PrintfArgFormatter : public BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char, FormatSpec> +{ +public: +    /** Constructs an argument formatter object. */ +    PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s) +        : BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char, FormatSpec>(w, s) +    { +    } +}; + +/** This template formats data and writes the output to a writer. */ +template<typename Char, typename ArgFormatter = PrintfArgFormatter<Char>> +class PrintfFormatter : private internal::FormatterBase +{ +private: +    BasicWriter<Char> &writer_; + +    void parse_flags(FormatSpec &spec, const Char *&s); + +    // Returns the argument with specified index or, if arg_index is equal +    // to the maximum unsigned value, the next argument. +    internal::Arg get_arg(const Char *s, unsigned arg_index = (std::numeric_limits<unsigned>::max)()); + +    // Parses argument index, flags and width and returns the argument index. +    unsigned parse_header(const Char *&s, FormatSpec &spec); + +public: +    /** +     \rst +     Constructs a ``PrintfFormatter`` object. References to the arguments and +     the writer are stored in the formatter object so make sure they have +     appropriate lifetimes. +     \endrst +     */ +    explicit PrintfFormatter(const ArgList &al, BasicWriter<Char> &w) +        : FormatterBase(al) +        , writer_(w) +    { +    } + +    /** Formats stored arguments and writes the output to the writer. */ +    void format(BasicCStringRef<Char> format_str); +}; + +template<typename Char, typename AF> +void PrintfFormatter<Char, AF>::parse_flags(FormatSpec &spec, const Char *&s) +{ +    for (;;) +    { +        switch (*s++) +        { +        case '-': +            spec.align_ = ALIGN_LEFT; +            break; +        case '+': +            spec.flags_ |= SIGN_FLAG | PLUS_FLAG; +            break; +        case '0': +            spec.fill_ = '0'; +            break; +        case ' ': +            spec.flags_ |= SIGN_FLAG; +            break; +        case '#': +            spec.flags_ |= HASH_FLAG; +            break; +        default: +            --s; +            return; +        } +    } +} + +template<typename Char, typename AF> +internal::Arg PrintfFormatter<Char, AF>::get_arg(const Char *s, unsigned arg_index) +{ +    (void)s; +    const char *error = FMT_NULL; +    internal::Arg arg = arg_index == std::numeric_limits<unsigned>::max() ? next_arg(error) : FormatterBase::get_arg(arg_index - 1, error); +    if (error) +        FMT_THROW(FormatError(!*s ? "invalid format string" : error)); +    return arg; +} + +template<typename Char, typename AF> +unsigned PrintfFormatter<Char, AF>::parse_header(const Char *&s, FormatSpec &spec) +{ +    unsigned arg_index = std::numeric_limits<unsigned>::max(); +    Char c = *s; +    if (c >= '0' && c <= '9') +    { +        // Parse an argument index (if followed by '$') or a width possibly +        // preceded with '0' flag(s). +        unsigned value = internal::parse_nonnegative_int(s); +        if (*s == '$') // value is an argument index +        { +            ++s; +            arg_index = value; +        } +        else +        { +            if (c == '0') +                spec.fill_ = '0'; +            if (value != 0) +            { +                // Nonzero value means that we parsed width and don't need to +                // parse it or flags again, so return now. +                spec.width_ = value; +                return arg_index; +            } +        } +    } +    parse_flags(spec, s); +    // Parse width. +    if (*s >= '0' && *s <= '9') +    { +        spec.width_ = internal::parse_nonnegative_int(s); +    } +    else if (*s == '*') +    { +        ++s; +        spec.width_ = internal::WidthHandler(spec).visit(get_arg(s)); +    } +    return arg_index; +} + +template<typename Char, typename AF> +void PrintfFormatter<Char, AF>::format(BasicCStringRef<Char> format_str) +{ +    const Char *start = format_str.c_str(); +    const Char *s = start; +    while (*s) +    { +        Char c = *s++; +        if (c != '%') +            continue; +        if (*s == c) +        { +            write(writer_, start, s); +            start = ++s; +            continue; +        } +        write(writer_, start, s - 1); + +        FormatSpec spec; +        spec.align_ = ALIGN_RIGHT; + +        // Parse argument index, flags and width. +        unsigned arg_index = parse_header(s, spec); + +        // Parse precision. +        if (*s == '.') +        { +            ++s; +            if ('0' <= *s && *s <= '9') +            { +                spec.precision_ = static_cast<int>(internal::parse_nonnegative_int(s)); +            } +            else if (*s == '*') +            { +                ++s; +                spec.precision_ = internal::PrecisionHandler().visit(get_arg(s)); +            } +            else +            { +                spec.precision_ = 0; +            } +        } + +        using internal::Arg; +        Arg arg = get_arg(s, arg_index); +        if (spec.flag(HASH_FLAG) && internal::IsZeroInt().visit(arg)) +            spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG); +        if (spec.fill_ == '0') +        { +            if (arg.type <= Arg::LAST_NUMERIC_TYPE) +                spec.align_ = ALIGN_NUMERIC; +            else +                spec.fill_ = ' '; // Ignore '0' flag for non-numeric types. +        } + +        // Parse length and convert the argument to the required type. +        using internal::ArgConverter; +        switch (*s++) +        { +        case 'h': +            if (*s == 'h') +                ArgConverter<signed char>(arg, *++s).visit(arg); +            else +                ArgConverter<short>(arg, *s).visit(arg); +            break; +        case 'l': +            if (*s == 'l') +                ArgConverter<fmt::LongLong>(arg, *++s).visit(arg); +            else +                ArgConverter<long>(arg, *s).visit(arg); +            break; +        case 'j': +            ArgConverter<intmax_t>(arg, *s).visit(arg); +            break; +        case 'z': +            ArgConverter<std::size_t>(arg, *s).visit(arg); +            break; +        case 't': +            ArgConverter<std::ptrdiff_t>(arg, *s).visit(arg); +            break; +        case 'L': +            // printf produces garbage when 'L' is omitted for long double, no +            // need to do the same. +            break; +        default: +            --s; +            ArgConverter<void>(arg, *s).visit(arg); +        } + +        // Parse type. +        if (!*s) +            FMT_THROW(FormatError("invalid format string")); +        spec.type_ = static_cast<char>(*s++); + +        if (spec.type_ == 's') +        { +            // set the format type to the default if 's' is specified +            spec.type_ = internal::DefaultType().visit(arg); +        } + +        if (arg.type <= Arg::LAST_INTEGER_TYPE) +        { +            // Normalize type. +            switch (spec.type_) +            { +            case 'i': +            case 'u': +                spec.type_ = 'd'; +                break; +            case 'c': +                // TODO: handle wchar_t +                internal::CharConverter(arg).visit(arg); +                break; +            } +        } + +        start = s; + +        // Format argument. +        AF(writer_, spec).visit(arg); +    } +    write(writer_, start, s); +} + +inline void printf(Writer &w, CStringRef format, ArgList args) +{ +    PrintfFormatter<char>(args, w).format(format); +} +FMT_VARIADIC(void, printf, Writer &, CStringRef) + +inline void printf(WWriter &w, WCStringRef format, ArgList args) +{ +    PrintfFormatter<wchar_t>(args, w).format(format); +} +FMT_VARIADIC(void, printf, WWriter &, WCStringRef) + +/** +  \rst +  Formats arguments and returns the result as a string. + +  **Example**:: + +    std::string message = fmt::sprintf("The answer is %d", 42); +  \endrst +*/ +inline std::string sprintf(CStringRef format, ArgList args) +{ +    MemoryWriter w; +    printf(w, format, args); +    return w.str(); +} +FMT_VARIADIC(std::string, sprintf, CStringRef) + +inline std::wstring sprintf(WCStringRef format, ArgList args) +{ +    WMemoryWriter w; +    printf(w, format, args); +    return w.str(); +} +FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef) + +/** +  \rst +  Prints formatted data to the file *f*. + +  **Example**:: + +    fmt::fprintf(stderr, "Don't %s!", "panic"); +  \endrst + */ +FMT_API int fprintf(std::FILE *f, CStringRef format, ArgList args); +FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef) + +/** +  \rst +  Prints formatted data to ``stdout``. + +  **Example**:: + +    fmt::printf("Elapsed time: %.2f seconds", 1.23); +  \endrst + */ +inline int printf(CStringRef format, ArgList args) +{ +    return fprintf(stdout, format, args); +} +FMT_VARIADIC(int, printf, CStringRef) + +/** +  \rst +  Prints formatted data to the stream *os*. + +  **Example**:: + +    fprintf(cerr, "Don't %s!", "panic"); +  \endrst + */ +inline int fprintf(std::ostream &os, CStringRef format_str, ArgList args) +{ +    MemoryWriter w; +    printf(w, format_str, args); +    internal::write(os, w); +    return static_cast<int>(w.size()); +} +FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef) +} // namespace fmt + +#ifdef FMT_HEADER_ONLY +#include "printf.cc" +#endif + +#endif // FMT_PRINTF_H_  | 
