{fmt} 在 Gecko 中

{fmt} 是 C++20 的 std::format 格式化 API 的库实现,该 API 支持类型感知字符串格式化。与 printf 不同,这种格式字符串样式不需要在格式字符串中指定每个格式参数的类型。例如,而不是

#include <mozilla/Sprintf.h>
#include <inttypes.h>
// ...
char buf[1024];
int64_t a = 123;
uint64_t a = 456;
auto literal = "A literal"_ns;
mozilla::SprintfBuf(buf, 1024,
                    "Formatting a number: %" PRId64
                    " and another one: " PRIu64
                    ", and finally a string: %s",
                    a, b, literal.get());

可以这样做

#include <fmt/format.h>
// ...
char buf[1024];
int64_t a = 123;
uint64_t a = 456;
auto literal = "A literal"_ns;
fmt::format_to_n(res, 1024,
                 FMT_STRING("Formatting a number: {} and another one: {} "
                            "and finally a string: {}"),
                 a, b, literal.get());

用户定义类型

可以对 用户定义类型 进行一次格式化,然后与 {fmt} 中的所有格式化函数一起使用。给定一个示例对象

struct POD {
  double mA;
  uint64_t mB;
};

可以编写如下自定义格式化程序

auto format_as(POD aInstance) -> std::string {
  return fmt::format(FMT_STRING("POD: mA: {}, mB: {}"), aInstance.mA,
                     aInstance.mB);
}

并按预期以各种方式使用它

char bufFmt[1024] = {};

POD p{4.3, 8};
auto [out, size] = fmt::format_to(bufFmt, "{}", p);
*out = 0; // Write the null terminator

assert(!strcmp("POD: mA: 4.3, mB: 8", bufFmt));
fmt::println(FMT_STRING("### debug: {}"), p);
fmt::print(stderr, FMT_STRING("### debug to stderr {}\n"), p);
MOZ_LOG_FMT(gLogModule, "Important: {}", p);

格式化序列

可以轻松地格式化可以使用基于范围的 for 循环的容器

nsTArray<uint8_t> array(4);
for (uint32_t i = 0; i < 4; i++) {
    array.AppendElement((123 * 5 * (i+1)) % 255);
}
auto [out, size] = fmt::format_to(bufFmt, FMT_STRING("{:#04x}"), fmt::join(array, ", "));
*out = 0; // Write the null terminator
ASSERT_STREQ("0x69, 0xd2, 0x3c, 0xa5", bufFmt);

MOZ_LOG 集成

MOZ_LOG_FMT 类似于 MOZ_LOG,但采用 {fmt} 样式的格式字符串

MOZ_LOG_FMT(gLogModule, "{}x{} = {}", 3, 3, 3*3);

MOZ_LOG 不同,无需在格式和参数列表周围添加额外的括号。

ns*String 集成

可以将 {fmt} 样式的格式字符串追加到 nsString,如下所示

nsCString aLovelyString("Here is a value: ");
aLovelyString.AppendFmt(FMT_SRING("{}"), 4);

nsString aLovelyWideString(u"Here are two values: ");
aLovelyString.AppendFmt(FMT_SRING(u"{}, {}"), 4, u"wide");

或直接使用 nsFmt[C]String

nsFmtCString str(FMT_STRING("{},{},{},{}"), 1, 1, 2, 3);
nsFmtString str(FMT_STRING(u"{},{},{},{}"), 1, 1, 2, u"wide string");
// use it as usual