Add std::format and fmt support (#5224)

*  add std::format and fmt support

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* ♻️ reorganize PR

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* 💚 fix build

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* 💚 fix build

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* 💚 fix build

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann
2026-07-02 15:59:36 +02:00
committed by GitHub
parent ca49ab6123
commit 8d7e0046f4
21 changed files with 824 additions and 0 deletions
+90
View File
@@ -79,6 +79,10 @@
#include <string_view>
#endif
#if JSON_HAS_STD_FORMAT
#include <format> // format_parse_context, format_context, formatter, format_error
#endif
/*!
@brief namespace for Niels Lohmann
@see https://github.com/nlohmann
@@ -5258,6 +5262,14 @@ std::string to_string(const NLOHMANN_BASIC_JSON_TPL& j)
return j.dump();
}
/// @brief user-defined format_as function for JSON values (fmt <= 11.0.x support)
/// @sa https://json.nlohmann.me/api/basic_json/format_as/
NLOHMANN_BASIC_JSON_TPL_DECLARATION
std::string format_as(const NLOHMANN_BASIC_JSON_TPL& j)
{
return j.dump();
}
inline namespace literals
{
inline namespace json_literals
@@ -5361,6 +5373,84 @@ inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC
#endif
#if JSON_HAS_STD_FORMAT
/// @brief std::formatter specialization for JSON values
/// @sa https://json.nlohmann.me/api/basic_json/std_formatter/
NLOHMANN_BASIC_JSON_TPL_DECLARATION
struct formatter<nlohmann::NLOHMANN_BASIC_JSON_TPL, char> // NOLINT(cert-dcl58-cpp)
{
// -1 means compact output (dump()); any value >= 0 means pretty-printed
// output with that many spaces (or indent_char) per level (dump(indent, indent_char)).
int indent = -1;
char indent_char = ' ';
constexpr auto parse(format_parse_context& ctx) -> format_parse_context::iterator
{
auto it = ctx.begin();
const auto end = ctx.end();
constexpr auto is_align = [](char c)
{
return c == '<' || c == '>' || c == '^';
};
// [[fill] align] - repurposed here to pick a custom indent character,
// e.g. "{:.>#4}" pretty-prints with '.' as the indent character
if (it != end && it + 1 != end && is_align(it[1]))
{
indent_char = *it;
it += 2;
}
else if (it != end && is_align(*it))
{
++it;
}
// ['#'] - "alternate form", used here to request pretty-printing with a
// default indent of 4 (overridden by an explicit width below, if given)
if (it != end && *it == '#')
{
indent = 4;
++it;
}
// [width] - repurposed here to pick the indent size for pretty-printing,
// e.g. "{:2}" or "{:#2}" pretty-print with an indent of 2; a width without
// '#' implies pretty-printing since an indent otherwise has no meaning
if (it != end && *it >= '1' && *it <= '9')
{
indent = 0;
while (it != end && *it >= '0' && *it <= '9')
{
indent = (indent * 10) + (*it - '0');
++it;
}
}
// sign, the '0' flag, precision, locale-specific formatting ('L'), dynamic
// width/precision ("{...}"), and type characters all have no meaning for
// JSON values; none of them are consumed above, so they all end up rejected
// by this single check along with any other unrecognized trailing spec.
if (it != end && *it != '}')
{
JSON_THROW(format_error("invalid format args for nlohmann::json"));
}
return it;
}
template<typename FormatContext>
auto format(const nlohmann::NLOHMANN_BASIC_JSON_TPL& j, FormatContext& ctx) const -> decltype(ctx.out())
{
// dump()'s own default (indent = -1) already means compact output, so this
// covers both the compact and pretty-printed cases without a branch.
const auto dumped = j.dump(indent, indent_char);
return std::copy(dumped.begin(), dumped.end(), ctx.out());
}
};
#endif
} // namespace std
#if JSON_USE_GLOBAL_UDLS