mirror of
https://github.com/fmtlib/fmt.git
synced 2025-06-25 09:21:41 +02:00
Enable constexpr support for fmt::format (fmtlib#3403) (#4456)
This commit is contained in:
@ -42,7 +42,7 @@ namespace detail {
|
||||
#endif
|
||||
|
||||
template <typename T, typename... Tail>
|
||||
auto first(const T& value, const Tail&...) -> const T& {
|
||||
constexpr auto first(const T& value, const Tail&...) -> const T& {
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -436,8 +436,8 @@ FMT_BEGIN_EXPORT
|
||||
template <typename CompiledFormat, typename... Args,
|
||||
typename Char = typename CompiledFormat::char_type,
|
||||
FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
|
||||
FMT_INLINE std::basic_string<Char> format(const CompiledFormat& cf,
|
||||
const Args&... args) {
|
||||
FMT_INLINE FMT_CONSTEXPR_STRING std::basic_string<Char> format(
|
||||
const CompiledFormat& cf, const Args&... args) {
|
||||
auto s = std::basic_string<Char>();
|
||||
cf.format(std::back_inserter(s), args...);
|
||||
return s;
|
||||
@ -452,8 +452,8 @@ constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf,
|
||||
|
||||
template <typename S, typename... Args,
|
||||
FMT_ENABLE_IF(is_compiled_string<S>::value)>
|
||||
FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
|
||||
Args&&... args) {
|
||||
FMT_INLINE FMT_CONSTEXPR_STRING std::basic_string<typename S::char_type> format(
|
||||
const S&, Args&&... args) {
|
||||
if constexpr (std::is_same<typename S::char_type, char>::value) {
|
||||
constexpr auto str = basic_string_view<typename S::char_type>(S());
|
||||
if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') {
|
||||
|
@ -117,6 +117,33 @@
|
||||
# define FMT_NOINLINE
|
||||
#endif
|
||||
|
||||
// Detect constexpr std::string.
|
||||
#if !FMT_USE_CONSTEVAL
|
||||
# define FMT_USE_CONSTEXPR_STRING 0
|
||||
#elif defined(__cpp_lib_constexpr_string) && \
|
||||
__cpp_lib_constexpr_string >= 201907L
|
||||
# if FMT_CLANG_VERSION && FMT_GLIBCXX_RELEASE
|
||||
// clang + libstdc++ are able to work only starting with gcc13.3
|
||||
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113294
|
||||
# if FMT_GLIBCXX_RELEASE < 13
|
||||
# define FMT_USE_CONSTEXPR_STRING 0
|
||||
# elif FMT_GLIBCXX_RELEASE == 13 && __GLIBCXX__ < 20240521
|
||||
# define FMT_USE_CONSTEXPR_STRING 0
|
||||
# else
|
||||
# define FMT_USE_CONSTEXPR_STRING 1
|
||||
# endif
|
||||
# else
|
||||
# define FMT_USE_CONSTEXPR_STRING 1
|
||||
# endif
|
||||
#else
|
||||
# define FMT_USE_CONSTEXPR_STRING 0
|
||||
#endif
|
||||
#if FMT_USE_CONSTEXPR_STRING
|
||||
# define FMT_CONSTEXPR_STRING constexpr
|
||||
#else
|
||||
# define FMT_CONSTEXPR_STRING
|
||||
#endif
|
||||
|
||||
// GCC 4.9 doesn't support qualified names in specializations.
|
||||
namespace std {
|
||||
template <typename T> struct iterator_traits<fmt::basic_appender<T>> {
|
||||
@ -4252,7 +4279,7 @@ FMT_NODISCARD FMT_INLINE auto format(format_string<T...> fmt, T&&... args)
|
||||
* std::string answer = fmt::to_string(42);
|
||||
*/
|
||||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
||||
FMT_NODISCARD auto to_string(T value) -> std::string {
|
||||
FMT_NODISCARD FMT_CONSTEXPR_STRING auto to_string(T value) -> std::string {
|
||||
// The buffer should be large enough to store the number including the sign
|
||||
// or "false" for bool.
|
||||
char buffer[max_of(detail::digits10<T>() + 2, 5)];
|
||||
@ -4260,13 +4287,15 @@ FMT_NODISCARD auto to_string(T value) -> std::string {
|
||||
}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(detail::use_format_as<T>::value)>
|
||||
FMT_NODISCARD auto to_string(const T& value) -> std::string {
|
||||
FMT_NODISCARD FMT_CONSTEXPR_STRING auto to_string(const T& value)
|
||||
-> std::string {
|
||||
return to_string(format_as(value));
|
||||
}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value &&
|
||||
!detail::use_format_as<T>::value)>
|
||||
FMT_NODISCARD auto to_string(const T& value) -> std::string {
|
||||
FMT_NODISCARD FMT_CONSTEXPR_STRING auto to_string(const T& value)
|
||||
-> std::string {
|
||||
auto buffer = memory_buffer();
|
||||
detail::write<char>(appender(buffer), value);
|
||||
return {buffer.data(), buffer.size()};
|
||||
|
@ -421,3 +421,49 @@ TEST(compile_time_formatting_test, multibyte_fill) {
|
||||
EXPECT_EQ("жж42", test_format<8>(FMT_COMPILE("{:ж>4}"), 42));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if FMT_USE_CONSTEXPR_STRING
|
||||
|
||||
TEST(compile_test, constexpr_format) {
|
||||
{
|
||||
constexpr auto result = []() {
|
||||
return fmt::format(FMT_COMPILE("{}"), 1) == "1";
|
||||
}();
|
||||
EXPECT_TRUE(result);
|
||||
}
|
||||
|
||||
{
|
||||
constexpr auto result = []() {
|
||||
return fmt::format(FMT_COMPILE("{:#b}"), 42) == "0b101010";
|
||||
}();
|
||||
EXPECT_TRUE(result);
|
||||
}
|
||||
|
||||
{
|
||||
constexpr auto result = []() {
|
||||
return "**-42" == fmt::format(FMT_COMPILE("{:*>5}"), -42);
|
||||
}();
|
||||
EXPECT_TRUE(result);
|
||||
}
|
||||
|
||||
{
|
||||
constexpr auto result = []() {
|
||||
return "10 " == fmt::format(FMT_COMPILE("{: ^3}"), 10);
|
||||
}();
|
||||
EXPECT_TRUE(result);
|
||||
}
|
||||
|
||||
{
|
||||
constexpr auto result = []() {
|
||||
return "42 is 42" == fmt::format(FMT_COMPILE("{} is {}"), 42, 42);
|
||||
}();
|
||||
EXPECT_TRUE(result);
|
||||
}
|
||||
|
||||
constexpr auto result = []() {
|
||||
return "This is a very huge int: 1234567890" == fmt::format(FMT_COMPILE("This is a very huge int: {}"), 1234567890);
|
||||
}();
|
||||
EXPECT_TRUE(result);
|
||||
}
|
||||
|
||||
#endif // FMT_USE_CONSTEXPR_STRING
|
||||
|
Reference in New Issue
Block a user