Add optional support (#3303)
This commit is contained in:
parent
3a69529e8b
commit
5b8302079d
@ -508,6 +508,7 @@ Standard Library Types Formatting
|
|||||||
* `std::thread::id <https://en.cppreference.com/w/cpp/thread/thread/id>`_
|
* `std::thread::id <https://en.cppreference.com/w/cpp/thread/thread/id>`_
|
||||||
* `std::monostate <https://en.cppreference.com/w/cpp/utility/variant/monostate>`_
|
* `std::monostate <https://en.cppreference.com/w/cpp/utility/variant/monostate>`_
|
||||||
* `std::variant <https://en.cppreference.com/w/cpp/utility/variant/variant>`_
|
* `std::variant <https://en.cppreference.com/w/cpp/utility/variant/variant>`_
|
||||||
|
* `std::optional <https://en.cppreference.com/w/cpp/utility/optional>`_
|
||||||
|
|
||||||
Formatting Variants
|
Formatting Variants
|
||||||
-------------------
|
-------------------
|
||||||
|
@ -29,6 +29,9 @@
|
|||||||
# if FMT_HAS_INCLUDE(<variant>)
|
# if FMT_HAS_INCLUDE(<variant>)
|
||||||
# include <variant>
|
# include <variant>
|
||||||
# endif
|
# endif
|
||||||
|
# if FMT_HAS_INCLUDE(<optional>)
|
||||||
|
# include <optional>
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// GCC 4 does not support FMT_HAS_INCLUDE.
|
// 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> {};
|
struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {};
|
||||||
FMT_END_NAMESPACE
|
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
|
#ifdef __cpp_lib_variant
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
template <typename Char> struct formatter<std::monostate, Char> {
|
template <typename Char> struct formatter<std::monostate, Char> {
|
||||||
|
@ -50,6 +50,34 @@ TEST(std_test, thread_id) {
|
|||||||
EXPECT_FALSE(fmt::format("{}", std::this_thread::get_id()).empty());
|
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) {
|
TEST(std_test, variant) {
|
||||||
#ifdef __cpp_lib_variant
|
#ifdef __cpp_lib_variant
|
||||||
EXPECT_EQ(fmt::format("{}", std::monostate{}), "monostate");
|
EXPECT_EQ(fmt::format("{}", std::monostate{}), "monostate");
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "fmt/color.h"
|
#include "fmt/color.h"
|
||||||
#include "fmt/ostream.h"
|
#include "fmt/ostream.h"
|
||||||
#include "fmt/ranges.h"
|
#include "fmt/ranges.h"
|
||||||
|
#include "fmt/std.h"
|
||||||
#include "gtest-extra.h" // Contains
|
#include "gtest-extra.h" // Contains
|
||||||
#include "util.h" // get_locale
|
#include "util.h" // get_locale
|
||||||
|
|
||||||
@ -588,4 +589,12 @@ TEST(locale_test, sign) {
|
|||||||
EXPECT_EQ(fmt::format(std::locale(), L"{:L}", -50), L"-50");
|
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
|
#endif // FMT_STATIC_THOUSANDS_SEPARATOR
|
||||||
|
Loading…
Reference in New Issue
Block a user