Cut down and minimalistic C++ string formatting library

nanofmt

https://github.com/potatoengine/nanofmt

License

Copyright (c) Sean Middleditch and contributors

nanofmt is released under the MIT license.

nanofmt uses the Dragonbox reference implementation which released under either the Apache License Version 2.0 with LLVM Exceptions or the Boost Software License Version 1.0.

Documentation

Exmaple

char buffer[128];

char const* const end = nanofmt::format_to_n(
        buffer,
        sizeof buffer,
        "Hello, {0}! You are visitor {1}.",
        user_name,
        visitor_count);

// void write_log(char const* str, size_t length);
write_log(buffer, end - buffer);

About

nanofmt aims to provide a lite-weight semi-compatible implementation of the excellent fmtlib. This can be used in environments or team cultures where neither std::format nor fmtlib are available for use.

The primary motivation for nanofmt is to minimize dependencies on standard C++ headers and to minimize compile time. nanofmt does not aim to offer the fastest runtime efficiency, the most features, fmtlib or std::format compatibility, nor the most portable implementation.

C++17 is required.

Most notably, nanofmt only supports the (v)format_to_n interfaces to basic char* buffers and does not support any other character type or output iterators. There are custom (v)format_to wrappers that work only with the provided buffer type, which itself is just a wrapper around char* buffers.

nanofmt does not aim to be a true drop-in replacement of fmtlib, even for the interfaces found in both libraries. Some interfaces have been modified to appeal more to "C with Classes" programmers; this is not a judgement of modern C++, just an acquiescence to the prevalent tastes and opinions in the industries targetted by nanofmt (primarily the AAA game industry).

When to Use nanofmt

If you're in doubt, use fmtlib! It is in almost every conceivable way more complete, more runtime efficient, more reliable, better maintained, more portable, and otherwise superior.

Use nanofmt if your organization or team has decided they won't use fmtlib because of its standard library dependencies or its large-ish header sizes.

Use nanofmt if your organization or team believes that snprintf is the superior formatting library, other than limitations created by C varargs.

When NOT to Use nanofmt

Literally anytime that you have the option of using std::format or fmtlib, you should prefer using those instead!

If you're not sure if nanofmt is the right fit for your project, then it isn't. :)

Owner
Sean Middleditch
Software engineer in the games industry. These are my personal works and are neither endorsed by nor related to my employer.
Sean Middleditch
Comments
  • `format_append_to` or similar

    `format_append_to` or similar

    The fmtlib/std::format interface has one very unfortunate design issue where the format_to_n requires a pointer and length.

    This means that you can't easily chain these calls together, as you must adjust both pointer and length on every call.

    An improved interface takes an end-pointer instead of a length, so the return value of the format calls can be chained together.

    Fitting this into the existing APIs without introducing weird overload shenanigans would be painful, though. Just adding/changing a format_to_n(char* dest, char* end, ...) overload could cause confusion/bugs on where the format_string argument comes in. (One option may be to make format_string not implicitly convert from char*?). Better may be a new function, e.g. something like format_append_to(char* dest, char* end, format_string, ...).

    format_to_n also doesn't NUL-terminate, but any format_append_to should NUL-terminate, so overloading that name is likely a very bad idea.

    Not terribly fond of having so many functions, though. I'd rather we trim down function names and overloads, not expand things further.

  • Name prefix configuration

    Name prefix configuration

    Enable configuring nanofmt to use name prefixes instead of C++ namespaces.

    Test case:

    • User can compile library so all public symbols have custom_ prefix instead of nanofmt:: namespace.
    • Two copies of the library compiled with different prefixes, or one with prefixes and one with namespaces, can link.
  • Resolve namespace ambiguities

    Resolve namespace ambiguities

    • Use namespace to reference make_format_args (avoids ambiguity with std::make_format_args or fmt::make_format_args, if those are pulled in via ADL for any reason)
    • Use fully-qualified namespaces
  • Revise `format_buffer` and `format_to` to buffers

    Revise `format_buffer` and `format_to` to buffers

    Fixes #32 Fixes #33

    • Rename format_buffer to format_output
    • Replace format_to, vformat_to, and format_value_to overloads that targeted a format_buffer with the format_output member functions format, vformat, format_value.
  • Rethink `format_to` overloads that target `format_buffer`

    Rethink `format_to` overloads that target `format_buffer`

    The behavior of formatting to a format_buffer is odd; should it NUL terminate or not?

    Perhaps, since format_buffer is normally interacted with using member functions, there instead should be .format() and .vformat() member functions instead of free function overloads?

    Free functions are nicer because they're composable, but I think since the behavior is slightly different than format_to to a character array, we may want different names, at least.

  • Rename `format_buffer`

    Rename `format_buffer`

    The name could be confused with an owning buffer.

    And an owning buffer would actually be a cheap and handy thing to include in nanofmt.

    Consider:

    • format_context - name used in fmtlib/std::format, but may be confusing since our interface would be different
    • format_output - seems direct and semi-clear
    • format_target - less clear, but maybe not as easily confused with output iterators?
    • format_dest - would be consistent with use of dest as the variable name, I guess
  • Refactor docs, address NUL termination

    Refactor docs, address NUL termination

    Fixes #29

    Only the (v)format(_value)_to functions NUL-terminate. Documents updated and tests added. [[nodiscard]] added to functions whose return char* should be used to calculate written length.

    • Restructure docs
    • Remove use of Doxygen, Breathe, and Exhale
    • Add [[nodiscard]] annotations
    • Remove foo_size functions to foo_length
    • Split format.h into format.inl
    • (v)format_to overload on format_buffer returns the buffer, explicitly does not NUL-terminate
  • Audit NUL termination of format functions

    Audit NUL termination of format functions

    Functions like format_to_n should not NUL-terminate, ensure documentation is correct.

    All versions of format_to should NUL-terminate.

    If we add other functions, like #28, ensure those NUL-terminate unless there's a darn good reason not to.

  • CMake install support

    CMake install support

    Fixes #26 Fixes #25

    • install targets
    • don't use dragonbox as a sub-package, since that makes it install too
    • give dragonbox a nanofmt-specific namespace so there won't be symbol clashes with other dragonbox versions
    • set high warning levels for internal and CI builds
  • Simplify formatters, remove constexpr

    Simplify formatters, remove constexpr

    Fixes #12 Fixes #22

    Remove the various format_*.h headers. Add the necessary specializations for core types, akin to what's in std::format, directly to format.h. All implementation details are in formatters.cpp.

    Added back a very thin format_string_view mostly just as a helper for specializations of string types that want to format a length-delimited string type.

  • Nuke `constexpr` support entirely (until C++20 modules)

    Nuke `constexpr` support entirely (until C++20 modules)

    Target users have indicated they'd never want to pay the "cost" of keeping these in headers.

    Can revisit adding constexpr support with Modules builds.

  • C++14 support

    C++14 support

    Add the ability to compile in C++14 mode.

    This mostly just means replacing use of if constexpr, likely only in C++14 builds given the cost of SFINAE overloads.

  • Design error handling

    Design error handling

    Currently, a malformed format spec, out of range argument, or other runtime problem just silently terminates formatting and returns.

    Design a "proper" error handling solution.

    Exceptions would not fit the target userbase. Possible options include:

    • terminate (with macro to replace call with custom termination handler?)
    • Return error code instead of, or in addition to, the char*
    • Add overloads that take an error code output parameter
    • Write detailed error string into output
    • Some combination of the above
  • Benchmark compilation

    Benchmark compilation

    Run some quality benchmarks comparing the compilation speed when using snprintf, fmtlib, and nanofmt.

    Investigate using the benchmark tools at https://github.com/fmtlib/format-benchmark for this task.

    Requirements:

    • Benchmark large scale tests on many TUs
    • Benchmark with and without PCHs
    • Benchmark with modules (requires #5)
    • Benchmark single TU with many format calls with different permutations of argument types
    • ??? moar benches
  • C++20 module

    C++20 module

    Add a C++20 module interface to nanofmt. This should not just be a header module unit.

    Success:

    • Module unit can be compiled on MSVC
    • Module unit can be imported on MSVC
    • Tests pass when using module imports
C++ functions matching the interface and behavior of python string methods with std::string

Pystring is a collection of C++ functions which match the interface and behavior of python's string class methods using std::string. Implemented in C+

Sep 28, 2022
A simple header-only C++ argument parser library. Supposed to be flexible and powerful, and attempts to be compatible with the functionality of the Python standard argparse library (though not necessarily the API).

args Note that this library is essentially in maintenance mode. I haven't had the time to work on it or give it the love that it deserves. I'm not add

Sep 22, 2022
A simple header-only C++ argument parser library. Supposed to be flexible and powerful, and attempts to be compatible with the functionality of the Python standard argparse library (though not necessarily the API).

args Note that this library is essentially in maintenance mode. I haven't had the time to work on it or give it the love that it deserves. I'm not add

Aug 31, 2021
A (relatively) small node library to clone and pull git repositories in a standalone manner thanks to libgit2, powered by WebAssembly and Emscripten

simple-git-wasm A (relatively) small node library to clone and pull git repositories in a standalone manner thanks to libgit2, powered by WebAssembly

May 20, 2022
A single header C++ library for parsing command line arguments and options with minimal amount of code

Quick Arg Parser Tired of unwieldy tools like getopt or argp? Quick Arg Parser is a single header C++ library for parsing command line arguments

Aug 10, 2022
Sep 22, 2022
A C, C++ and Rust library to draw graphics with pixels in the terminal
A C, C++ and Rust library to draw graphics with pixels in the terminal

A library to draw graphics with pixels in the terminal Who needs a GUI when you have a terminal ? Building To generate libpluto.a, run: $ make To ins

Sep 3, 2022
C++ Library for pulling system and hardware information, without hitting the command line.

infoware C++ Library for pulling system and hardware information, without hitting the command line. Requirements No non-built-in ones by default. Some

Sep 17, 2022
A small self-contained alternative to readline and libedit that supports UTF-8 and Windows and is BSD licensed.

Linenoise Next Generation A small, portable GNU readline replacement for Linux, Windows and MacOS which is capable of handling UTF-8 characters. Unlik

Sep 27, 2022
A readline and libedit replacement that supports UTF-8, syntax highlighting, hints and Windows and is BSD licensed.
A readline and libedit replacement that supports UTF-8, syntax highlighting, hints and Windows and is BSD licensed.

Read Evaluate Print Loop ++ A small, portable GNU readline replacement for Linux, Windows and MacOS which is capable of handling UTF-8 characters. Unl

Sep 25, 2022
A library for interactive command line interfaces in modern C++
A library for interactive command line interfaces in modern C++

cli A cross-platform header only C++14 library for interactive command line interfaces (Cisco style) Features Header only Cross-platform (linux and wi

Sep 24, 2022
PDCurses - a curses library for environments that don't fit the termcap/terminfo model.

Welcome to PDCurses! PDCurses is an implementation of X/Open curses for multiple platforms. The latest version can be found at: https://pdcurses.org/

Oct 1, 2022
Library for writing text-based user interfaces

IMPORTANT This library is no longer maintained. It's pretty small if you have a big project that relies on it, just maintain it yourself. Or look for

Sep 17, 2022
Small header only C++ library for writing multiplatform terminal applications

Terminal Terminal is small header only library for writing terminal applications. It works on Linux, macOS and Windows (in the native cmd.exe console)

Sep 22, 2022
A command parsing library

LampOpt操作文档 概述 LampOpt是一个基于C++的控制台命令解析库,优点是体型小、适应全平台、方便易用。 引用 可选择在IDE中直接在引用目录中添加odt.h,或直接与需编译文件放在同一目录下,并引用: #include "odt.h" 使用 odt.h头文件内定义了一个名为LampOp

Aug 21, 2022
A single-class C++ library for reading animated GIF files

EasyGifReader EasyGifReader is a single-class C++ library that aims to simplify reading an animated GIF file. It is built on top of and depends on gif

Sep 3, 2022
Library for creating terminal applications with text-based widgets
Library for creating terminal applications with text-based widgets

Library for creating terminal applications with text-based widgets FINAL CUT is a C++ class library and widget toolkit with full mouse support for cre

Sep 27, 2022
The gflags package contains a C++ library that implements commandline flags processing.

The gflags package contains a C++ library that implements commandline flags processing. It includes built-in support for standard types such as string and the ability to define flags in the source file in which they are used. Online documentation available at:

Sep 21, 2022
This is a simple CLI interface helper library for C.

LIBCCLI This is a very simple shell like interface for CLI activities. More will be added to this, but for now, this is the basic idea:

Sep 24, 2022