Add optional support (#3303)

This commit is contained in:
tom-huntington 2023-02-26 03:45:56 +13:00 committed by GitHub
parent 3a69529e8b
commit 5b8302079d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 84 additions and 0 deletions

View File

@ -508,6 +508,7 @@ Standard Library Types Formatting
* `std::thread::id <https://en.cppreference.com/w/cpp/thread/thread/id>`_
* `std::monostate <https://en.cppreference.com/w/cpp/utility/variant/monostate>`_
* `std::variant <https://en.cppreference.com/w/cpp/utility/variant/variant>`_
* `std::optional <https://en.cppreference.com/w/cpp/utility/optional>`_
Formatting Variants
-------------------

View File

@ -29,6 +29,9 @@
# if FMT_HAS_INCLUDE(<variant>)
# include <variant>
# endif
# if FMT_HAS_INCLUDE(<optional>)
# include <optional>
# endif
#endif
// GCC 4 does not support FMT_HAS_INCLUDE.
@ -91,6 +94,49 @@ template <typename Char>
struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {};
FMT_END_NAMESPACE
#ifdef __cpp_lib_optional
FMT_BEGIN_NAMESPACE
template <typename T, typename Char>
struct formatter<std::optional<T>, Char,
std::enable_if_t<is_formattable<T, Char>::value>> {
private:
formatter<T, Char> underlying_;
static constexpr basic_string_view<Char> optional =
detail::string_literal<Char, 'o', 'p', 't', 'i', 'o', 'n', 'a', 'l',
'('>{};
static constexpr basic_string_view<Char> none =
detail::string_literal<Char, 'n', 'o', 'n', 'e'>{};
template <class U>
FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, bool set)
-> decltype(u.set_debug_format(set)) {
u.set_debug_format(set);
}
template <class U>
FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {}
public:
template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) {
maybe_set_debug_format(underlying_, true);
return underlying_.parse(ctx);
}
template <typename FormatContext>
auto format(std::optional<T> const& opt, FormatContext& ctx) const
-> decltype(ctx.out()) {
if (!opt) return detail::write<Char>(ctx.out(), none);
auto out = ctx.out();
out = detail::write<Char>(out, optional);
ctx.advance_to(out);
out = underlying_.format(*opt, ctx);
return detail::write(out, ')');
}
};
FMT_END_NAMESPACE
#endif // __cpp_lib_optional
#ifdef __cpp_lib_variant
FMT_BEGIN_NAMESPACE
template <typename Char> struct formatter<std::monostate, Char> {

View File

@ -50,6 +50,34 @@ TEST(std_test, thread_id) {
EXPECT_FALSE(fmt::format("{}", std::this_thread::get_id()).empty());
}
TEST(std_test, optional) {
#ifdef __cpp_lib_optional
EXPECT_EQ(fmt::format("{}", std::optional<int>{}), "none");
EXPECT_EQ(fmt::format("{}", std::pair{1, "second"}), "(1, \"second\")");
EXPECT_EQ(fmt::format("{}", std::vector{std::optional{1}, std::optional{2},
std::optional{3}}),
"[optional(1), optional(2), optional(3)]");
EXPECT_EQ(
fmt::format("{}", std::optional<std::optional<const char*>>{{"nested"}}),
"optional(optional(\"nested\"))");
EXPECT_EQ(
fmt::format("{:<{}}", std::optional{std::string{"left aligned"}}, 30),
"optional(\"left aligned\" )");
EXPECT_EQ(
fmt::format("{::d}", std::optional{std::vector{'h', 'e', 'l', 'l', 'o'}}),
"optional([104, 101, 108, 108, 111])");
EXPECT_EQ(fmt::format("{}", std::optional{std::string{"string"}}),
"optional(\"string\")");
EXPECT_EQ(fmt::format("{}", std::optional{'C'}), "optional(\'C\')");
EXPECT_EQ(fmt::format("{:.{}f}", std::optional{3.14}, 1), "optional(3.1)");
struct unformattable {};
EXPECT_FALSE((fmt::is_formattable<unformattable>::value));
EXPECT_FALSE((fmt::is_formattable<std::optional<unformattable>>::value));
EXPECT_TRUE((fmt::is_formattable<std::optional<int>>::value));
#endif
}
TEST(std_test, variant) {
#ifdef __cpp_lib_variant
EXPECT_EQ(fmt::format("{}", std::monostate{}), "monostate");

View File

@ -16,6 +16,7 @@
#include "fmt/color.h"
#include "fmt/ostream.h"
#include "fmt/ranges.h"
#include "fmt/std.h"
#include "gtest-extra.h" // Contains
#include "util.h" // get_locale
@ -588,4 +589,12 @@ TEST(locale_test, sign) {
EXPECT_EQ(fmt::format(std::locale(), L"{:L}", -50), L"-50");
}
TEST(std_test_xchar, optional) {
# ifdef __cpp_lib_optional
EXPECT_EQ(fmt::format(L"{}", std::optional{L'C'}), L"optional(\'C\')");
EXPECT_EQ(fmt::format(L"{}", std::optional{std::wstring{L"wide string"}}),
L"optional(\"wide string\")");
# endif
}
#endif // FMT_STATIC_THOUSANDS_SEPARATOR