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
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;
}
@ -504,8 +504,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_CONSTEXPR20 FMT_INLINE 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;
@ -520,8 +520,8 @@ constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf,
template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
Args&&... args) {
FMT_INLINE FMT_CONSTEXPR20 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] == '}') {

View File

@ -825,11 +825,11 @@ constexpr auto has_const_formatter() -> bool {
// Extracts a reference to the container from back_insert_iterator.
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& {
using base = std::back_insert_iterator<Container>;
struct accessor : base {
accessor(base b) : base(b) {}
FMT_CONSTEXPR accessor(base b) : base(b) {}
using base::container;
};
return *accessor(it).container;
@ -933,7 +933,8 @@ template <typename T> class 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& {
return ptr_[index];
@ -1493,8 +1494,8 @@ class appender : public std::back_insert_iterator<detail::buffer<char>> {
appender(base it) noexcept : base(it) {}
FMT_UNCHECKED_ITERATOR(appender);
auto operator++() noexcept -> appender& { return *this; }
auto operator++(int) noexcept -> appender { return *this; }
FMT_CONSTEXPR20 auto operator++() noexcept -> appender& { return *this; }
FMT_CONSTEXPR20 auto operator++(int) noexcept -> appender { return *this; }
};
// 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 {
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);
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.
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];
}
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();
}
@ -574,7 +575,7 @@ template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)>
#if FMT_CLANG_VERSION >= 307 && !FMT_ICC_VERSION
__attribute__((no_sanitize("undefined")))
#endif
inline auto
inline FMT_CONSTEXPR auto
reserve(std::back_insert_iterator<Container> it, size_t n)
-> checked_ptr<typename Container::value_type> {
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)>
inline auto base_iterator(std::back_insert_iterator<Container>& it,
checked_ptr<typename Container::value_type>)
inline FMT_CONSTEXPR auto base_iterator(
std::back_insert_iterator<Container>& it,
checked_ptr<typename Container::value_type>)
-> std::back_insert_iterator<Container> {
return it;
}
@ -875,13 +877,14 @@ using is_double_double = bool_constant<std::numeric_limits<T>::digits == 106>;
template <typename T>
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) {
auto count = to_unsigned(end - begin);
try_reserve(size_ + count);
auto free_cap = capacity_ - size_;
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;
begin += count;
}
@ -4462,14 +4465,15 @@ auto join(Range&& range, string_view sep)
\endrst
*/
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();
detail::write<char>(appender(buffer), value);
return {buffer.data(), buffer.size()};
}
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
// or "false" for bool.
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("true ", test_format<6>(FMT_COMPILE("{:5}"), 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) {