Skip to content

Commit 0363675

Browse files
committed
Enable constexpr support for fmt::format (#3403)
1 parent 3ba3c39 commit 0363675

File tree

4 files changed

+98
-8
lines changed

4 files changed

+98
-8
lines changed

include/fmt/base.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,33 @@
141141
# define FMT_CONSTEXPR20
142142
#endif
143143

144+
// Detect constexpr std::string.
145+
#if !FMT_USE_CONSTEVAL
146+
# define FMT_USE_CONSTEXPR_STRING 0
147+
#elif !defined(__cpp_lib_constexpr_string)
148+
# define FMT_USE_CONSTEXPR_STRING 0
149+
#elif defined(__cpp_lib_constexpr_string) && \
150+
__cpp_lib_constexpr_string < 201907L
151+
# define FMT_USE_CONSTEXPR_STRING 0
152+
#elif FMT_CLANG_VERSION && FMT_GLIBCXX_RELEASE
153+
// clang is able to work only start with gcc13.3
154+
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113294
155+
# if FMT_GLIBCXX_RELEASE < 13
156+
# define FMT_USE_CONSTEXPR_STRING 0
157+
# elif defined(__GLIBCXX__) && __GLIBCXX__ < 20240521
158+
# define FMT_USE_CONSTEXPR_STRING 0
159+
# else
160+
# define FMT_USE_CONSTEXPR_STRING 1
161+
# endif
162+
#else
163+
# define FMT_USE_CONSTEXPR_STRING 1
164+
#endif
165+
#if FMT_USE_CONSTEXPR_STRING
166+
# define FMT_CONSTEXPR_STRING constexpr
167+
#else
168+
# define FMT_CONSTEXPR_STRING
169+
#endif
170+
144171
// Check if exceptions are disabled.
145172
#ifdef FMT_USE_EXCEPTIONS
146173
// Use the provided definition.

include/fmt/compile.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ namespace detail {
4242
#endif
4343

4444
template <typename T, typename... Tail>
45-
auto first(const T& value, const Tail&...) -> const T& {
45+
FMT_CONSTEXPR auto first(const T& value, const Tail&...) -> const T& {
4646
return value;
4747
}
4848

@@ -436,8 +436,8 @@ FMT_BEGIN_EXPORT
436436
template <typename CompiledFormat, typename... Args,
437437
typename Char = typename CompiledFormat::char_type,
438438
FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
439-
FMT_INLINE std::basic_string<Char> format(const CompiledFormat& cf,
440-
const Args&... args) {
439+
FMT_INLINE FMT_CONSTEXPR_STRING std::basic_string<Char> format(
440+
const CompiledFormat& cf, const Args&... args) {
441441
auto s = std::basic_string<Char>();
442442
cf.format(std::back_inserter(s), args...);
443443
return s;
@@ -452,8 +452,8 @@ constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf,
452452

453453
template <typename S, typename... Args,
454454
FMT_ENABLE_IF(is_compiled_string<S>::value)>
455-
FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
456-
Args&&... args) {
455+
FMT_INLINE FMT_CONSTEXPR_STRING std::basic_string<typename S::char_type> format(
456+
const S&, Args&&... args) {
457457
if constexpr (std::is_same<typename S::char_type, char>::value) {
458458
constexpr auto str = basic_string_view<typename S::char_type>(S());
459459
if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') {

include/fmt/format.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4207,21 +4207,21 @@ FMT_NODISCARD FMT_INLINE auto format(format_string<T...> fmt, T&&... args)
42074207
* std::string answer = fmt::to_string(42);
42084208
*/
42094209
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
4210-
FMT_NODISCARD auto to_string(T value) -> std::string {
4210+
FMT_NODISCARD FMT_CONSTEXPR_STRING auto to_string(T value) -> std::string {
42114211
// The buffer should be large enough to store the number including the sign
42124212
// or "false" for bool.
42134213
char buffer[max_of(detail::digits10<T>() + 2, 5)];
42144214
return {buffer, detail::write<char>(buffer, value)};
42154215
}
42164216

42174217
template <typename T, FMT_ENABLE_IF(detail::use_format_as<T>::value)>
4218-
FMT_NODISCARD auto to_string(const T& value) -> std::string {
4218+
FMT_NODISCARD FMT_CONSTEXPR_STRING auto to_string(const T& value) -> std::string {
42194219
return to_string(format_as(value));
42204220
}
42214221

42224222
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value &&
42234223
!detail::use_format_as<T>::value)>
4224-
FMT_NODISCARD auto to_string(const T& value) -> std::string {
4224+
FMT_NODISCARD FMT_CONSTEXPR_STRING auto to_string(const T& value) -> std::string {
42254225
auto buffer = memory_buffer();
42264226
detail::write<char>(appender(buffer), value);
42274227
return {buffer.data(), buffer.size()};

test/compile-test.cc

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,3 +421,66 @@ TEST(compile_time_formatting_test, multibyte_fill) {
421421
EXPECT_EQ("жж42", test_format<8>(FMT_COMPILE("{:ж>4}"), 42));
422422
}
423423
#endif
424+
425+
#if FMT_USE_CONSTEXPR_STRING
426+
427+
TEST(compile_test, constexpr_format) {
428+
{
429+
constexpr auto result = []() {
430+
return fmt::format(FMT_COMPILE("{}"), true) == "true";
431+
}();
432+
EXPECT_TRUE(result);
433+
}
434+
435+
{
436+
constexpr auto result = []() {
437+
return fmt::format(FMT_COMPILE("{:6}"), false) == "false ";
438+
}();
439+
EXPECT_TRUE(result);
440+
}
441+
442+
{
443+
constexpr auto result = []() {
444+
return fmt::format(FMT_COMPILE("{:d}"), true) == "1";
445+
}();
446+
EXPECT_TRUE(result);
447+
}
448+
449+
{
450+
constexpr auto result = []() {
451+
return fmt::format(FMT_COMPILE("{:#b}"), 42) == "0b101010";
452+
}();
453+
EXPECT_TRUE(result);
454+
}
455+
456+
{
457+
constexpr auto result = []() {
458+
return "**-42" == fmt::format(FMT_COMPILE("{:*>5}"), -42);
459+
}();
460+
EXPECT_TRUE(result);
461+
}
462+
463+
{
464+
constexpr auto result = []() {
465+
return "c " == fmt::format(FMT_COMPILE("{:3}"), 'c');
466+
}();
467+
EXPECT_TRUE(result);
468+
}
469+
470+
{
471+
constexpr auto result = []() {
472+
return "The answer is 42" ==
473+
fmt::format(FMT_COMPILE("{} is {}"), "The answer", "42");
474+
}();
475+
EXPECT_TRUE(result);
476+
}
477+
478+
{
479+
constexpr auto result = []() {
480+
return "bar" == fmt::format(FMT_COMPILE("{:b}"), test_formattable());
481+
}();
482+
EXPECT_TRUE(result);
483+
}
484+
}
485+
486+
#endif // FMT_USE_CONSTEXPR_STRING

0 commit comments

Comments
 (0)