Skip to content

Commit

Permalink
Move fmt::format to fmt/format.h
Browse files Browse the repository at this point in the history
  • Loading branch information
vitaut committed Jan 10, 2024
1 parent fc8f6ba commit b10ca99
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 144 deletions.
58 changes: 0 additions & 58 deletions include/fmt/base.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,39 +15,6 @@
#include <cstddef> // std::byte
#include <type_traits> // std::enable_if

#if defined(_LIBCPP_VERSION)
# define FMT_BEGIN_NAMESPACE_STD _LIBCPP_BEGIN_NAMESPACE_STD
# define FMT_END_NAMESPACE_STD _LIBCPP_END_NAMESPACE_STD
# define FMT_STD_TEMPLATE_VIS _LIBCPP_TEMPLATE_VIS
# define FMT_BEGIN_NAMESPACE_CXX11
# define FMT_END_NAMESPACE_CXX11
#elif defined(_GLIBCXX_RELEASE)
# define FMT_BEGIN_NAMESPACE_STD \
namespace std _GLIBCXX_VISIBILITY(default) { \
_GLIBCXX_BEGIN_NAMESPACE_VERSION
# define FMT_END_NAMESPACE_STD \
_GLIBCXX_END_NAMESPACE_VERSION \
}
# define FMT_STD_TEMPLATE_VIS
# if defined(_GLIBCXX_USE_CXX11_ABI)
# define FMT_BEGIN_NAMESPACE_CXX11 inline _GLIBCXX_BEGIN_NAMESPACE_CXX11
# define FMT_END_NAMESPACE_CXX11 _GLIBCXX_END_NAMESPACE_CXX11
# endif
#else
# include <string>
#endif

#ifdef FMT_BEGIN_NAMESPACE_STD
FMT_BEGIN_NAMESPACE_STD
template <typename Char> struct FMT_STD_TEMPLATE_VIS char_traits;
template <typename T> class FMT_STD_TEMPLATE_VIS allocator;
FMT_BEGIN_NAMESPACE_CXX11
template <typename Char, typename Traits, typename Allocator>
class FMT_STD_TEMPLATE_VIS basic_string;
FMT_END_NAMESPACE_CXX11
FMT_END_NAMESPACE_STD
#endif // FMT_BEGIN_NAMESPACE_STD

// The fmt library version in the form major * 10000 + minor * 100 + patch.
#define FMT_VERSION 100202

Expand Down Expand Up @@ -474,14 +441,8 @@ inline auto get_container(OutputIt it) -> typename OutputIt::container_type& {
}
} // namespace detail

template <typename Char>
using basic_string =
std::basic_string<Char, std::char_traits<Char>, std::allocator<Char>>;

// Checks whether T is a container with contiguous storage.
template <typename T> struct is_contiguous : std::false_type {};
template <typename Char>
struct is_contiguous<basic_string<Char>> : std::true_type {};

/**
An implementation of ``std::basic_string_view`` for pre-C++17. It provides a
Expand Down Expand Up @@ -2803,25 +2764,6 @@ using format_string = basic_format_string<char, type_identity_t<Args>...>;
inline auto runtime(string_view s) -> runtime_format_string<> { return {{s}}; }
#endif

FMT_API auto vformat(string_view fmt, format_args args) -> basic_string<char>;

/**
\rst
Formats ``args`` according to specifications in ``fmt`` and returns the result
as a string.
**Example**::
#include <fmt/core.h>
std::string message = fmt::format("The answer is {}.", 42);
\endrst
*/
template <typename... T, typename Char = char>
FMT_NODISCARD FMT_INLINE auto format(format_string<T...> fmt, T&&... args)
-> basic_string<Char> {
return vformat(fmt, fmt::make_format_args(args...));
}

/** Formats a string and writes the output to ``out``. */
template <typename OutputIt,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
Expand Down
4 changes: 4 additions & 0 deletions include/fmt/core.h
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
// This file is only provided for compatibility an may be removed in future
// versions. Use fmt/base.h if you don't need fmt::format and fmt/format.h
// otherwise.

#include "format.h"
19 changes: 19 additions & 0 deletions include/fmt/format.h
Original file line number Diff line number Diff line change
Expand Up @@ -4448,6 +4448,25 @@ constexpr auto operator""_a(const char* s, size_t) -> detail::udl_arg<char> {
} // namespace literals
#endif // FMT_USE_USER_DEFINED_LITERALS

FMT_API auto vformat(string_view fmt, format_args args) -> std::string;

/**
\rst
Formats ``args`` according to specifications in ``fmt`` and returns the result
as a string.
**Example**::
#include <fmt/core.h>
std::string message = fmt::format("The answer is {}.", 42);
\endrst
*/
template <typename... T>
FMT_NODISCARD FMT_INLINE auto format(format_string<T...> fmt, T&&... args)
-> std::string {
return vformat(fmt, fmt::make_format_args(args...));
}

template <typename Locale, FMT_ENABLE_IF(detail::is_locale<Locale>::value)>
inline auto vformat(const Locale& loc, string_view fmt, format_args args)
-> std::string {
Expand Down
98 changes: 12 additions & 86 deletions test/core-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,9 @@ TEST(core_test, is_formattable) {

static_assert(!fmt::is_formattable<convertible_to_pointer>::value, "");
const auto f = convertible_to_pointer_formattable();
EXPECT_EQ(fmt::format("{}", f), "test");
auto s = std::string();
fmt::format_to(std::back_inserter(s), "{}", f);
EXPECT_EQ(s, "test");

static_assert(!fmt::is_formattable<void (*)()>::value, "");

Expand All @@ -685,8 +687,6 @@ TEST(core_test, is_formattable) {
static_assert(!fmt::is_formattable<unformattable_scoped_enum>::value, "");
}

TEST(core_test, format) { EXPECT_EQ(fmt::format("{}", 42), "42"); }

TEST(core_test, format_to) {
auto s = std::string();
fmt::format_to(std::back_inserter(s), "{}", 42);
Expand All @@ -695,49 +695,18 @@ TEST(core_test, format_to) {

#ifdef __cpp_lib_byte
TEST(core_test, format_byte) {
EXPECT_EQ(fmt::format("{}", std::byte(42)), "42");
auto s = std::string();
fmt::format_to(std::back_inserter(s), "{}", std::byte(42));
EXPECT_EQ(s, "42");
}
#endif

struct convertible_to_int {
operator int() const { return 42; }
};

struct convertible_to_cstring {
operator const char*() const { return "foo"; }
};

FMT_BEGIN_NAMESPACE
template <> struct formatter<convertible_to_int> {
FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
auto format(convertible_to_int, format_context& ctx) const
-> decltype(ctx.out()) {
return copy("foo", ctx.out());
}
};

template <> struct formatter<convertible_to_cstring> {
FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
auto format(convertible_to_cstring, format_context& ctx) const
-> decltype(ctx.out()) {
return copy("bar", ctx.out());
}
};
FMT_END_NAMESPACE

TEST(core_test, formatter_overrides_implicit_conversion) {
EXPECT_EQ(fmt::format("{}", convertible_to_int()), "foo");
EXPECT_EQ(fmt::format("{}", convertible_to_cstring()), "bar");
}

// Test that check is not found by ADL.
template <typename T> void check(T);
TEST(core_test, adl_check) {
EXPECT_EQ(fmt::format("{}", test_struct()), "test");
auto s = std::string();
fmt::format_to(std::back_inserter(s), "{}", test_struct());
EXPECT_EQ(s, "test");
}

struct implicitly_convertible_to_string_view {
Expand Down Expand Up @@ -788,27 +757,6 @@ TEST(core_test, format_explicitly_convertible_to_std_string_view) {
# endif
#endif

namespace adl_test {
template <typename... T> void make_format_args(const T&...) = delete;

struct string : std::string {};
} // namespace adl_test

// Test that formatting functions compile when make_format_args is found by ADL.
TEST(core_test, adl) {
// Only check compilation and don't run the code to avoid polluting the output
// and since the output is tested elsewhere.
if (fmt::detail::const_check(true)) return;
auto s = adl_test::string();
char buf[10];
(void)fmt::format("{}", s);
fmt::format_to(buf, "{}", s);
fmt::format_to_n(buf, 10, "{}", s);
(void)fmt::formatted_size("{}", s);
fmt::print("{}", s);
fmt::print(stdout, "{}", s);
}

TEST(core_test, has_const_formatter) {
EXPECT_TRUE((fmt::detail::has_const_formatter<const_formattable,
fmt::format_context>()));
Expand All @@ -817,31 +765,9 @@ TEST(core_test, has_const_formatter) {
}

TEST(core_test, format_nonconst) {
EXPECT_EQ(fmt::format("{}", nonconst_formattable()), "test");
}

struct its_a_trap {
template <typename T> operator T() const {
auto v = T();
v.x = 42;
return v;
}
};

FMT_BEGIN_NAMESPACE
template <> struct formatter<its_a_trap> {
FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}

auto format(its_a_trap, format_context& ctx) const -> decltype(ctx.out()) {
return copy("42", ctx.out());
}
};
FMT_END_NAMESPACE

TEST(core_test, trappy_conversion) {
EXPECT_EQ(fmt::format("{}", its_a_trap()), "42");
auto s = std::string();
fmt::format_to(std::back_inserter(s), "{}", nonconst_formattable());
EXPECT_EQ(s, "test");
}

TEST(core_test, throw_in_buffer_dtor) {
Expand Down
82 changes: 82 additions & 0 deletions test/format-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2259,3 +2259,85 @@ FMT_END_NAMESPACE
TEST(format_test, formatter_nonconst_char) {
EXPECT_EQ(fmt::format("{}", convertible_to_nonconst_cstring()), "bar");
}

namespace adl_test {
template <typename... T> void make_format_args(const T&...) = delete;

struct string : std::string {};
} // namespace adl_test

// Test that formatting functions compile when make_format_args is found by ADL.
TEST(format_test, adl) {
// Only check compilation and don't run the code to avoid polluting the output
// and since the output is tested elsewhere.
if (fmt::detail::const_check(true)) return;
auto s = adl_test::string();
char buf[10];
(void)fmt::format("{}", s);
fmt::format_to(buf, "{}", s);
fmt::format_to_n(buf, 10, "{}", s);
(void)fmt::formatted_size("{}", s);
fmt::print("{}", s);
fmt::print(stdout, "{}", s);
}

struct its_a_trap {
template <typename T> operator T() const {
auto v = T();
v.x = 42;
return v;
}
};

FMT_BEGIN_NAMESPACE
template <> struct formatter<its_a_trap> {
FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}

auto format(its_a_trap, format_context& ctx) const -> decltype(ctx.out()) {
auto out = ctx.out();
*out++ = 'x';
return out;
}
};
FMT_END_NAMESPACE

TEST(format_test, trappy_conversion) {
EXPECT_EQ(fmt::format("{}", its_a_trap()), "x");
}

struct convertible_to_int {
operator int() const { return 42; }
};

struct convertible_to_cstring {
operator const char*() const { return "foo"; }
};

FMT_BEGIN_NAMESPACE
template <> struct formatter<convertible_to_int> {
FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
auto format(convertible_to_int, format_context& ctx) const
-> decltype(ctx.out()) {
return fmt::format_to(ctx.out(), "foo");
}
};

template <> struct formatter<convertible_to_cstring> {
FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
auto format(convertible_to_cstring, format_context& ctx) const
-> decltype(ctx.out()) {
return fmt::format_to(ctx.out(), "bar");
}
};
FMT_END_NAMESPACE

TEST(format_test, formatter_overrides_implicit_conversion) {
EXPECT_EQ(fmt::format("{}", convertible_to_int()), "foo");
EXPECT_EQ(fmt::format("{}", convertible_to_cstring()), "bar");
}

0 comments on commit b10ca99

Please sign in to comment.