ext-fmt/doc/api.md

652 lines
19 KiB
Markdown
Raw Normal View History

2024-06-01 16:05:17 +00:00
# API Reference
2024-06-01 14:02:03 +00:00
2024-06-02 14:01:40 +00:00
The {fmt} library API consists of the following components:
2024-06-01 14:02:03 +00:00
- [`fmt/base.h`](#base-api): the base API providing main formatting functions
for `char`/UTF-8 with C++20 compile-time checks and minimal dependencies
- [`fmt/format.h`](#format-api): the full format API providing additional
formatting functions and locale support
- [`fmt/ranges.h`](#ranges-api): formatting of ranges and tuples
- [`fmt/chrono.h`](#chrono-api): date and time formatting
- [`fmt/std.h`](#std-api): formatters for standard library types
- [`fmt/compile.h`](#compile-api): format string compilation
- [`fmt/color.h`](#color-api): terminal color and text style
- [`fmt/os.h`](#os-api): system APIs
- [`fmt/ostream.h`](#ostream-api): `std::ostream` support
- [`fmt/args.h`](#args-api): dynamic argument lists
- [`fmt/printf.h`](#printf-api): `printf` formatting
- [`fmt/xchar.h`](#xchar-api): optional `wchar_t` support
All functions and types provided by the library reside in namespace `fmt`
and macros have prefix `FMT_`.
## Base API
`fmt/base.h` defines the base API which provides main formatting functions
for `char`/UTF-8 with C++20 compile-time checks. It has minimal include
dependencies for better compile times. This header is only beneficial when
using {fmt} as a library (the default) and not in the header-only mode.
It also provides `formatter` specializations for the following types:
- `int`, `unsigned`, `long long`, `unsigned long long`
- `float`, `double`, `long double`
- `bool`
- `char`
- `const char*`, `fmt::string_view`
- `const void*`
The following functions use [format string syntax](syntax.md) similar to that
of [str.format](https://docs.python.org/3/library/stdtypes.html#str.format)
in Python. They take *fmt* and *args* as arguments.
*fmt* is a format string that contains literal text and replacement fields
surrounded by braces `{}`. The fields are replaced with formatted arguments
in the resulting string. [\~fmt::format_string]{.title-ref} is a format string
which can be implicitly constructed from a string literal or a `constexpr`
string and is checked at compile time in C++20. To pass a runtime format
string wrap it in [fmt::runtime]{.title-ref}.
*args* is an argument list representing objects to be formatted.
I/O errors are reported as [`std::system_error`](
https://en.cppreference.com/w/cpp/error/system_error) exceptions unless
specified otherwise.
<a id="print"></a>
::: print(format_string<T...>, T&&...)
::: print(FILE*, format_string<T...>, T&&...)
::: println(format_string<T...>, T&&...)
::: println(FILE*, format_string<T...>, T&&...)
::: format_to(OutputIt&&, format_string<T...>, T&&...)
::: format_to_n(OutputIt, size_t, format_string<T...>, T&&...)
::: format_to_n_result
2024-06-02 00:45:06 +00:00
::: formatted_size(format_string<T...>, T&&...)
2024-06-01 14:02:03 +00:00
2024-06-01 16:05:17 +00:00
<a id="udt"></a>
### Formatting User-Defined Types
2024-06-01 14:02:03 +00:00
The {fmt} library provides formatters for many standard C++ types.
See [`fmt/ranges.h`](#ranges-api) for ranges and tuples including standard
containers such as `std::vector`, [`fmt/chrono.h`](#chrono-api) for date and
time formatting and [`fmt/std.h`](#std-api) for other standard library types.
There are two ways to make a user-defined type formattable: providing a
`format_as` function or specializing the `formatter` struct template.
Use `format_as` if you want to make your type formattable as some other
type with the same format specifiers. The `format_as` function should
take an object of your type and return an object of a formattable type.
It should be defined in the same namespace as your type.
Example ([run](https://godbolt.org/z/nvME4arz8)):
#include <fmt/format.h>
namespace kevin_namespacy {
2024-06-01 21:40:39 +00:00
2024-06-01 14:02:03 +00:00
enum class film {
house_of_cards, american_beauty, se7en = 7
};
2024-06-01 21:40:39 +00:00
2024-06-01 14:02:03 +00:00
auto format_as(film f) { return fmt::underlying(f); }
2024-06-01 21:40:39 +00:00
2024-06-01 14:02:03 +00:00
}
int main() {
fmt::print("{}\n", kevin_namespacy::film::se7en); // prints "7"
}
Using specialization is more complex but gives you full control over
parsing and formatting. To use this method specialize the `formatter`
struct template for your type and implement `parse` and `format`
methods.
The recommended way of defining a formatter is by reusing an existing
one via inheritance or composition. This way you can support standard
format specifiers without implementing them yourself. For example:
2024-06-02 14:01:40 +00:00
```c++
// color.h:
#include <fmt/base.h>
2024-06-01 14:02:03 +00:00
2024-06-02 14:01:40 +00:00
enum class color {red, green, blue};
2024-06-01 14:02:03 +00:00
2024-06-02 14:01:40 +00:00
template <> struct fmt::formatter<color>: formatter<string_view> {
// parse is inherited from formatter<string_view>.
2024-06-01 14:02:03 +00:00
2024-06-02 14:01:40 +00:00
auto format(color c, format_context& ctx) const
-> format_context::iterator;
};
```
2024-06-01 14:02:03 +00:00
2024-06-02 14:01:40 +00:00
```c++
// color.cc:
#include "color.h"
#include <fmt/format.h>
2024-06-01 14:02:03 +00:00
2024-06-02 14:01:40 +00:00
auto fmt::formatter<color>::format(color c, format_context& ctx) const
-> format_context::iterator {
string_view name = "unknown";
switch (c) {
case color::red: name = "red"; break;
case color::green: name = "green"; break;
case color::blue: name = "blue"; break;
}
return formatter<string_view>::format(name, ctx);
}
```
2024-06-01 14:02:03 +00:00
Note that `formatter<string_view>::format` is defined in `fmt/format.h`
so it has to be included in the source file. Since `parse` is inherited
from `formatter<string_view>` it will recognize all string format
specifications, for example
2024-06-02 00:45:06 +00:00
```c++
2024-06-01 14:02:03 +00:00
fmt::format("{:>10}", color::blue)
```
will return `" blue"`.
The experimental `nested_formatter` provides an easy way of applying a
formatter to one or more subobjects.
For example:
#include <fmt/format.h>
struct point {
double x, y;
};
template <>
struct fmt::formatter<point> : nested_formatter<double> {
auto format(point p, format_context& ctx) const {
return write_padded(ctx, [=](auto out) {
return format_to(out, "({}, {})", this->nested(p.x),
this->nested(p.y));
});
}
};
int main() {
fmt::print("[{:>20.2f}]", point{1, 2});
}
prints:
[ (1.00, 2.00)]
Notice that fill, align and width are applied to the whole object which
is the recommended behavior while the remaining specifiers apply to
elements.
In general the formatter has the following form:
template <> struct fmt::formatter<T> {
// Parses format specifiers and stores them in the formatter.
//
// [ctx.begin(), ctx.end()) is a, possibly empty, character range that
// contains a part of the format string starting from the format
// specifications to be parsed, e.g. in
//
// fmt::format("{:f} continued", ...);
//
// the range will contain "f} continued". The formatter should parse
// specifiers until '}' or the end of the range. In this example the
// formatter should parse the 'f' specifier and return an iterator
// pointing to '}'.
constexpr auto parse(format_parse_context& ctx)
-> format_parse_context::iterator;
// Formats value using the parsed format specification stored in this
// formatter and writes the output to ctx.out().
auto format(const T& value, format_context& ctx) const
-> format_context::iterator;
};
It is recommended to at least support fill, align and width that apply
to the whole object and have the same semantics as in standard
formatters.
You can also write a formatter for a hierarchy of classes:
2024-06-02 14:01:40 +00:00
```c++
// demo.h:
#include <type_traits>
#include <fmt/core.h>
struct A {
virtual ~A() {}
virtual std::string name() const { return "A"; }
};
struct B : A {
virtual std::string name() const { return "B"; }
};
template <typename T>
struct fmt::formatter<T, std::enable_if_t<std::is_base_of<A, T>::value, char>> :
fmt::formatter<std::string> {
auto format(const A& a, format_context& ctx) const {
return fmt::formatter<std::string>::format(a.name(), ctx);
}
};
```
2024-06-01 14:02:03 +00:00
2024-06-02 14:01:40 +00:00
```c++
// demo.cc:
#include "demo.h"
#include <fmt/format.h>
2024-06-01 14:02:03 +00:00
2024-06-02 14:01:40 +00:00
int main() {
B b;
A& a = b;
fmt::print("{}", a); // prints "B"
}
```
2024-06-01 14:02:03 +00:00
Providing both a `formatter` specialization and a `format_as` overload
is disallowed.
2024-06-02 00:45:06 +00:00
### Compile-Time Format String Checks
Compile-time format string checks are enabled by default on compilers
that support C++20 `consteval`. On older compilers you can use the
[FMT_STRING](legacy-checks>) macro defined in `fmt/format.h` instead.
Unused arguments are allowed as in Python's `str.format` and ordinary functions.
::: basic_format_string
::: format_string
::: runtime(string_view)
2024-06-01 14:02:03 +00:00
### Named Arguments
::: arg(const Char*, const T&)
Named arguments are not supported in compile-time checks at the moment.
### Type Erasure
2024-06-01 14:02:03 +00:00
You can create your own formatting function with compile-time checks and
2024-06-02 00:45:06 +00:00
small binary footprint, for example ([run](https://godbolt.org/z/b9Pbasvzc)):
2024-06-01 14:02:03 +00:00
2024-06-01 21:40:39 +00:00
```c++
2024-06-02 03:08:41 +00:00
#include <fmt/format.h>
2024-06-01 14:02:03 +00:00
2024-06-01 21:40:39 +00:00
void vlog(const char* file, int line,
2024-06-02 00:45:06 +00:00
fmt::string_view fmt, fmt::format_args args) {
fmt::print("{}: {}: {}", file, line, fmt::vformat(fmt, args));
2024-06-01 14:02:03 +00:00
}
template <typename... T>
2024-06-01 21:40:39 +00:00
void log(const char* file, int line,
2024-06-02 00:45:06 +00:00
fmt::format_string<T...> fmt, T&&... args) {
vlog(file, line, fmt, fmt::make_format_args(args...));
2024-06-01 14:02:03 +00:00
}
2024-06-02 00:45:06 +00:00
#define MY_LOG(fmt, ...) log(__FILE__, __LINE__, fmt, __VA_ARGS__)
2024-06-01 14:02:03 +00:00
MY_LOG("invalid squishiness: {}", 42);
```
Note that `vlog` is not parameterized on argument types which improves
compile times and reduces binary code size compared to a fully
parameterized version.
::: make_format_args(T&...)
::: basic_format_args
2024-06-02 00:45:06 +00:00
::: format_args
2024-06-01 14:02:03 +00:00
2024-06-02 00:45:06 +00:00
::: basic_format_arg
2024-06-01 14:02:03 +00:00
2024-06-02 00:45:06 +00:00
::: basic_format_parse_context
2024-06-01 14:02:03 +00:00
2024-06-02 00:45:06 +00:00
::: context
2024-06-01 14:02:03 +00:00
2024-06-02 00:45:06 +00:00
::: format_context
2024-06-01 14:02:03 +00:00
### Compatibility
2024-06-02 00:45:06 +00:00
::: basic_string_view
2024-06-01 14:02:03 +00:00
2024-06-02 00:45:06 +00:00
::: string_view
2024-06-01 14:02:03 +00:00
## Format API
`fmt/format.h` defines the full format API providing additional
formatting functions and locale support.
<a id="format"></a>
::: format(format_string<T...>, T&&...)
::: vformat(string_view, format_args)
### Utilities
::: ptr(T)
::: underlying(Enum)
::: to_string(const T&)
::: group_digits(T)
2024-06-02 14:01:40 +00:00
::: detail::buffer
2024-06-01 14:02:03 +00:00
::: basic_memory_buffer
### System Errors
{fmt} does not use `errno` to communicate errors to the user, but it may
call system functions which set `errno`. Users should not make any
assumptions about the value of `errno` being preserved by library
functions.
::: system_error
::: format_system_error
2024-06-02 00:45:06 +00:00
### Literal-Based API
The following user-defined literals are defined in `fmt/format.h`.
::: operator""_a()
2024-06-01 14:02:03 +00:00
### Custom Allocators
The {fmt} library supports custom dynamic memory allocators. A custom
allocator class can be specified as a template argument to
`fmt::basic_memory_buffer`{.interpreted-text role="class"}:
using custom_memory_buffer =
fmt::basic_memory_buffer<char, fmt::inline_buffer_size, custom_allocator>;
It is also possible to write a formatting function that uses a custom
allocator:
using custom_string =
std::basic_string<char, std::char_traits<char>, custom_allocator>;
custom_string vformat(custom_allocator alloc, fmt::string_view format_str,
fmt::format_args args) {
auto buf = custom_memory_buffer(alloc);
fmt::vformat_to(std::back_inserter(buf), format_str, args);
return custom_string(buf.data(), buf.size(), alloc);
}
template <typename ...Args>
inline custom_string format(custom_allocator alloc,
fmt::string_view format_str,
const Args& ... args) {
return vformat(alloc, format_str, fmt::make_format_args(args...));
}
The allocator will be used for the output container only. Formatting
functions normally don\'t do any allocations for built-in and string
types except for non-default floating-point formatting that occasionally
falls back on `sprintf`.
### Locale
All formatting is locale-independent by default. Use the `'L'` format
specifier to insert the appropriate number separator characters from the
locale:
#include <fmt/core.h>
#include <locale>
std::locale::global(std::locale("en_US.UTF-8"));
auto s = fmt::format("{:L}", 1000000); // s == "1,000,000"
`fmt/format.h` provides the following overloads of formatting functions
that take `std::locale` as a parameter. The locale type is a template
parameter to avoid the expensive `<locale>` include.
::: format(const Locale&, format_string<T...>, T&&...)
::: format_to(OutputIt, const Locale&, format_string<T...>, T&&...)
::: formatted_size(const Locale&, format_string<T...>, T&&...)
2024-06-02 00:45:06 +00:00
<a id="legacy-checks"></a>
### Legacy Compile-Time Format String Checks
2024-06-01 14:02:03 +00:00
`FMT_STRING` enables compile-time checks on older compilers. It requires
C++14 or later and is a no-op in C++11.
2024-06-02 15:26:56 +00:00
::: FMT_STRING
2024-06-01 14:02:03 +00:00
To force the use of legacy compile-time checks, define the preprocessor
variable `FMT_ENFORCE_COMPILE_STRING`. When set, functions accepting
`FMT_STRING` will fail to compile with regular strings.
2024-06-02 00:45:06 +00:00
<a id="ranges-api"></a>
## Range and Tuple Formatting
2024-06-01 14:02:03 +00:00
The library also supports convenient formatting of ranges and tuples:
#include <fmt/ranges.h>
std::tuple<char, int, float> t{'a', 1, 2.0f};
// Prints "('a', 1, 2.0)"
fmt::print("{}", t);
Using `fmt::join`, you can separate tuple elements with a custom
separator:
#include <fmt/ranges.h>
std::tuple<int, char> t = {1, 'a'};
// Prints "1, a"
fmt::print("{}", fmt::join(t, ", "));
::: join(Range&&, string_view)
::: join(It, Sentinel, string_view)
2024-06-02 00:45:06 +00:00
<a id="chrono-api"></a>
## Date and Time Formatting
2024-06-01 14:02:03 +00:00
`fmt/chrono.h` provides formatters for
- [std::chrono::duration](https://en.cppreference.com/w/cpp/chrono/duration)
- [std::chrono::time_point](https://en.cppreference.com/w/cpp/chrono/time_point)
- [std::tm](https://en.cppreference.com/w/cpp/chrono/c/tm)
The format syntax is described in [Chrono Format Specifications](syntax.md#
chrono-format-specifications).
**Example**:
#include <fmt/chrono.h>
int main() {
std::time_t t = std::time(nullptr);
// Prints "The date is 2020-11-07." (with the current date):
fmt::print("The date is {:%Y-%m-%d}.", fmt::localtime(t));
using namespace std::literals::chrono_literals;
// Prints "Default format: 42s 100ms":
fmt::print("Default format: {} {}\n", 42s, 100ms);
// Prints "strftime-like format: 03:15:30":
fmt::print("strftime-like format: {:%H:%M:%S}\n", 3h + 15min + 30s);
}
::: localtime(std::time_t)
::: gmtime(std::time_t)
<a id="std-api"></a>
## Standard Library Types Formatting
2024-06-01 14:02:03 +00:00
`fmt/std.h` provides formatters for:
- [`std::atomic`](https://en.cppreference.com/w/cpp/atomic/atomic)
- [`std::atomic_flag`](https://en.cppreference.com/w/cpp/atomic/atomic_flag)
- [`std::bitset`](https://en.cppreference.com/w/cpp/utility/bitset)
- [`std::error_code`](https://en.cppreference.com/w/cpp/error/error_code)
- [`std::filesystem::path`](https://en.cppreference.com/w/cpp/filesystem/path)
- [`std::monostate`](https://en.cppreference.com/w/cpp/utility/variant/monostate)
- [`std::optional`](https://en.cppreference.com/w/cpp/utility/optional)
- [`std::source_location`](https://en.cppreference.com/w/cpp/utility/source_location)
- [`std::thread::id`](https://en.cppreference.com/w/cpp/thread/thread/id)
- [`std::variant`](https://en.cppreference.com/w/cpp/utility/variant/variant)
::: ptr(const std::unique_ptr<T, Deleter>&)
::: ptr(const std::shared_ptr<T>&)
### Formatting Variants
A `std::variant` is only formattable if every variant alternative is
formattable, and requires the `__cpp_lib_variant` [library
feature](https://en.cppreference.com/w/cpp/feature_test).
**Example**:
#include <fmt/std.h>
2024-06-02 03:08:41 +00:00
fmt::print("{}", std::variant<char, float>('x'));
// Output: variant('x')
2024-06-01 14:02:03 +00:00
2024-06-02 03:08:41 +00:00
fmt::print("{}", std::variant<std::monostate, char>());
// Output: variant(monostate)
2024-06-01 14:02:03 +00:00
2024-06-02 03:08:41 +00:00
<a id="compile-api"></a>
## Format String Compilation
2024-06-01 14:02:03 +00:00
`fmt/compile.h` provides format string compilation enabled via the
`FMT_COMPILE` macro or the `_cf` user-defined literal. Format strings
marked with `FMT_COMPILE` or `_cf` are parsed, checked and converted
into efficient formatting code at compile-time. This supports arguments
of built-in and string types as well as user-defined types with `format`
functions taking the format context type as a template parameter in
their `formatter` specializations. For example:
template <> struct fmt::formatter<point> {
constexpr auto parse(format_parse_context& ctx);
template <typename FormatContext>
auto format(const point& p, FormatContext& ctx) const;
};
Format string compilation can generate more binary code compared to the
default API and is only recommended in places where formatting is a
performance bottleneck.
::: FMT_COMPILE
2024-06-01 14:02:03 +00:00
::: operator""_cf
<a id="color-api"></a>
## Terminal Color and Text Style
2024-06-01 14:02:03 +00:00
`fmt/color.h` provides support for terminal color and text style output.
::: print(const text_style&, format_string<T...>, T&&...)
::: fg(detail::color_type)
2024-06-02 00:45:06 +00:00
::: bg(detail::color_type)
2024-06-01 14:02:03 +00:00
2024-06-02 00:45:06 +00:00
::: styled(const T&, text_style)
2024-06-01 14:02:03 +00:00
<a id="os-api"></a>
## System APIs
2024-06-01 14:02:03 +00:00
2024-06-02 00:45:06 +00:00
::: ostream
2024-06-01 14:02:03 +00:00
2024-06-02 00:45:06 +00:00
::: windows_error
2024-06-01 14:02:03 +00:00
<a id="ostream-api"></a>
## `std::ostream` Support
2024-06-01 14:02:03 +00:00
`fmt/ostream.h` provides `std::ostream` support including formatting of
user-defined types that have an overloaded insertion operator
(`operator<<`). In order to make a type formattable via `std::ostream`
you should provide a `formatter` specialization inherited from
`ostream_formatter`:
#include <fmt/ostream.h>
struct date {
int year, month, day;
friend std::ostream& operator<<(std::ostream& os, const date& d) {
return os << d.year << '-' << d.month << '-' << d.day;
}
};
template <> struct fmt::formatter<date> : ostream_formatter {};
std::string s = fmt::format("The date is {}", date{2012, 12, 9});
// s == "The date is 2012-12-9"
2024-06-02 00:45:06 +00:00
::: streamed(const T&)
2024-06-01 14:02:03 +00:00
2024-06-02 00:45:06 +00:00
::: print(std::ostream&, format_string<T...>, T&&...)
<a id="args-api"></a>
## Dynamic Argument Lists
2024-06-02 00:45:06 +00:00
The header `fmt/args.h` provides `dynamic_format_arg_store`, a builder-like API
that can be used to construct format argument lists dynamically.
::: dynamic_format_arg_store
2024-06-01 14:02:03 +00:00
<a id="printf-api"></a>
## `printf` Formatting
2024-06-01 14:02:03 +00:00
The header `fmt/printf.h` provides `printf`-like formatting
functionality. The following functions use [printf format string
syntax](https://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html)
with the POSIX extension for positional arguments. Unlike their standard
counterparts, the `fmt` functions are type-safe and throw an exception
if an argument type doesn\'t match its format specification.
2024-06-02 00:45:06 +00:00
::: printf(string_view, const T&...)
2024-06-01 14:02:03 +00:00
2024-06-02 00:45:06 +00:00
::: fprintf(std::FILE*, const S&, const T&...)
2024-06-01 14:02:03 +00:00
2024-06-02 00:45:06 +00:00
::: sprintf(const S&, const T&...)
2024-06-01 14:02:03 +00:00
2024-06-02 03:08:41 +00:00
<a id="xchar-api"></a>
## Wide Strings
2024-06-01 14:02:03 +00:00
The optional header `fmt/xchar.h` provides support for `wchar_t` and
exotic character types.
2024-06-02 03:08:41 +00:00
::: is_char
2024-06-01 14:02:03 +00:00
2024-06-02 03:08:41 +00:00
::: wstring_view
2024-06-01 14:02:03 +00:00
2024-06-02 03:08:41 +00:00
::: wformat_context
2024-06-01 14:02:03 +00:00
2024-06-02 03:08:41 +00:00
::: to_wstring(const T&)
2024-06-01 14:02:03 +00:00
## Compatibility with C++20 `std::format`
{fmt} implements nearly all of the [C++20 formatting
library](https://en.cppreference.com/w/cpp/utility/format) with the
following differences:
- Names are defined in the `fmt` namespace instead of `std` to avoid
collisions with standard library implementations.
- Width calculation doesn\'t use grapheme clusterization. The latter has
been implemented in a separate branch but hasn\'t been integrated yet.