constexpr for compiled fmt

This commit is contained in:
Shawn Zhong 2023-04-29 04:54:30 -05:00
parent f8c9fabd94
commit eaf8c1b772
4 changed files with 30 additions and 20 deletions

View File

@ -135,7 +135,7 @@ struct udl_compiled_string : compiled_string {
#endif #endif
template <typename T, typename... Tail> template <typename T, typename... Tail>
const T& first(const T& value, const Tail&...) { FMT_CONSTEXPR const T& first(const T& value, const Tail&...) {
return value; return value;
} }
@ -504,8 +504,8 @@ FMT_BEGIN_EXPORT
template <typename CompiledFormat, typename... Args, template <typename CompiledFormat, typename... Args,
typename Char = typename CompiledFormat::char_type, typename Char = typename CompiledFormat::char_type,
FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)> FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
FMT_INLINE std::basic_string<Char> format(const CompiledFormat& cf, FMT_CONSTEXPR20 FMT_INLINE std::basic_string<Char> format(
const Args&... args) { const CompiledFormat& cf, const Args&... args) {
auto s = std::basic_string<Char>(); auto s = std::basic_string<Char>();
cf.format(std::back_inserter(s), args...); cf.format(std::back_inserter(s), args...);
return s; return s;
@ -520,8 +520,8 @@ constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf,
template <typename S, typename... Args, template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
FMT_INLINE std::basic_string<typename S::char_type> format(const S&, FMT_INLINE FMT_CONSTEXPR20 std::basic_string<typename S::char_type> format(
Args&&... args) { const S&, Args&&... args) {
if constexpr (std::is_same<typename S::char_type, char>::value) { if constexpr (std::is_same<typename S::char_type, char>::value) {
constexpr auto str = basic_string_view<typename S::char_type>(S()); constexpr auto str = basic_string_view<typename S::char_type>(S());
if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') { if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') {

View File

@ -825,11 +825,11 @@ constexpr auto has_const_formatter() -> bool {
// Extracts a reference to the container from back_insert_iterator. // Extracts a reference to the container from back_insert_iterator.
template <typename Container> template <typename Container>
inline auto get_container(std::back_insert_iterator<Container> it) FMT_CONSTEXPR inline auto get_container(std::back_insert_iterator<Container> it)
-> Container& { -> Container& {
using base = std::back_insert_iterator<Container>; using base = std::back_insert_iterator<Container>;
struct accessor : base { struct accessor : base {
accessor(base b) : base(b) {} FMT_CONSTEXPR accessor(base b) : base(b) {}
using base::container; using base::container;
}; };
return *accessor(it).container; return *accessor(it).container;
@ -933,7 +933,8 @@ template <typename T> class buffer {
} }
/** Appends data to the end of the buffer. */ /** Appends data to the end of the buffer. */
template <typename U> void append(const U* begin, const U* end); template <typename U>
void FMT_CONSTEXPR append(const U* begin, const U* end);
template <typename Idx> FMT_CONSTEXPR auto operator[](Idx index) -> T& { template <typename Idx> FMT_CONSTEXPR auto operator[](Idx index) -> T& {
return ptr_[index]; return ptr_[index];
@ -1493,8 +1494,8 @@ class appender : public std::back_insert_iterator<detail::buffer<char>> {
appender(base it) noexcept : base(it) {} appender(base it) noexcept : base(it) {}
FMT_UNCHECKED_ITERATOR(appender); FMT_UNCHECKED_ITERATOR(appender);
auto operator++() noexcept -> appender& { return *this; } FMT_CONSTEXPR20 auto operator++() noexcept -> appender& { return *this; }
auto operator++(int) noexcept -> appender { return *this; } FMT_CONSTEXPR20 auto operator++(int) noexcept -> appender { return *this; }
}; };
// A formatting argument. It is a trivially copyable/constructible type to // A formatting argument. It is a trivially copyable/constructible type to
@ -1604,7 +1605,8 @@ FMT_CONSTEXPR FMT_INLINE auto visit_format_arg(
namespace detail { namespace detail {
template <typename Char, typename InputIt> template <typename Char, typename InputIt>
auto copy_str(InputIt begin, InputIt end, appender out) -> appender { FMT_CONSTEXPR20 auto copy_str(InputIt begin, InputIt end, appender out)
-> appender {
get_container(out).append(begin, end); get_container(out).append(begin, end);
return out; return out;
} }

View File

@ -546,11 +546,12 @@ template <typename T> using sentinel_t = decltype(std::end(std::declval<T&>()));
// A workaround for std::string not having mutable data() until C++17. // A workaround for std::string not having mutable data() until C++17.
template <typename Char> template <typename Char>
inline auto get_data(std::basic_string<Char>& s) -> Char* { inline FMT_CONSTEXPR auto get_data(std::basic_string<Char>& s) -> Char* {
return &s[0]; return &s[0];
} }
template <typename Container> template <typename Container>
inline auto get_data(Container& c) -> typename Container::value_type* { inline FMT_CONSTEXPR auto get_data(Container& c) ->
typename Container::value_type* {
return c.data(); return c.data();
} }
@ -574,7 +575,7 @@ template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)>
#if FMT_CLANG_VERSION >= 307 && !FMT_ICC_VERSION #if FMT_CLANG_VERSION >= 307 && !FMT_ICC_VERSION
__attribute__((no_sanitize("undefined"))) __attribute__((no_sanitize("undefined")))
#endif #endif
inline auto inline FMT_CONSTEXPR auto
reserve(std::back_insert_iterator<Container> it, size_t n) reserve(std::back_insert_iterator<Container> it, size_t n)
-> checked_ptr<typename Container::value_type> { -> checked_ptr<typename Container::value_type> {
Container& c = get_container(it); Container& c = get_container(it);
@ -612,8 +613,9 @@ template <typename T> auto to_pointer(buffer_appender<T> it, size_t n) -> T* {
} }
template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)> template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)>
inline auto base_iterator(std::back_insert_iterator<Container>& it, inline FMT_CONSTEXPR auto base_iterator(
checked_ptr<typename Container::value_type>) std::back_insert_iterator<Container>& it,
checked_ptr<typename Container::value_type>)
-> std::back_insert_iterator<Container> { -> std::back_insert_iterator<Container> {
return it; return it;
} }
@ -875,13 +877,14 @@ using is_double_double = bool_constant<std::numeric_limits<T>::digits == 106>;
template <typename T> template <typename T>
template <typename U> template <typename U>
void buffer<T>::append(const U* begin, const U* end) { FMT_CONSTEXPR void buffer<T>::append(const U* begin, const U* end) {
while (begin != end) { while (begin != end) {
auto count = to_unsigned(end - begin); auto count = to_unsigned(end - begin);
try_reserve(size_ + count); try_reserve(size_ + count);
auto free_cap = capacity_ - size_; auto free_cap = capacity_ - size_;
if (free_cap < count) count = free_cap; if (free_cap < count) count = free_cap;
std::uninitialized_copy_n(begin, count, make_checked(ptr_ + size_, count)); auto out = make_checked(ptr_ + size_, count);
for (size_t i = 0; i < count; ++i) *out++ = begin[i];
size_ += count; size_ += count;
begin += count; begin += count;
} }
@ -4462,14 +4465,15 @@ auto join(Range&& range, string_view sep)
\endrst \endrst
*/ */
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)> template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
inline auto to_string(const T& value) -> std::string { FMT_NODISCARD FMT_CONSTEXPR20 inline auto to_string(const T& value)
-> std::string {
auto buffer = memory_buffer(); auto buffer = memory_buffer();
detail::write<char>(appender(buffer), value); detail::write<char>(appender(buffer), value);
return {buffer.data(), buffer.size()}; return {buffer.data(), buffer.size()};
} }
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
FMT_NODISCARD inline auto to_string(T value) -> std::string { FMT_NODISCARD FMT_CONSTEXPR20 inline auto to_string(T value) -> std::string {
// The buffer should be large enough to store the number including the sign // The buffer should be large enough to store the number including the sign
// or "false" for bool. // or "false" for bool.
constexpr int max_size = detail::digits10<T>() + 2; constexpr int max_size = detail::digits10<T>() + 2;

View File

@ -327,6 +327,10 @@ TEST(compile_time_formatting_test, bool) {
EXPECT_EQ("false", test_format<6>(FMT_COMPILE("{}"), false)); EXPECT_EQ("false", test_format<6>(FMT_COMPILE("{}"), false));
EXPECT_EQ("true ", test_format<6>(FMT_COMPILE("{:5}"), true)); EXPECT_EQ("true ", test_format<6>(FMT_COMPILE("{:5}"), true));
EXPECT_EQ("1", test_format<2>(FMT_COMPILE("{:d}"), true)); EXPECT_EQ("1", test_format<2>(FMT_COMPILE("{:d}"), true));
static_assert(fmt::format(FMT_COMPILE("{}"), true) == "true");
static_assert(fmt::format(FMT_COMPILE("{}"), false) == "false");
static_assert(fmt::format(FMT_COMPILE("{:5}"), true) == "true ");
static_assert(fmt::format(FMT_COMPILE("{:d}"), true) == "1");
} }
TEST(compile_time_formatting_test, integer) { TEST(compile_time_formatting_test, integer) {