Enable FMT_STRING() use with types other than string literals
This commit is contained in:
parent
08ca40ea91
commit
4c04162df7
@ -371,6 +371,9 @@ template <typename Char> class basic_string_view {
|
|||||||
the size with ``std::char_traits<Char>::length``.
|
the size with ``std::char_traits<Char>::length``.
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
|
#if __cplusplus >= 201703L // C++17's char_traits::length() is constexpr.
|
||||||
|
FMT_CONSTEXPR
|
||||||
|
#endif
|
||||||
basic_string_view(const Char* s)
|
basic_string_view(const Char* s)
|
||||||
: data_(s), size_(std::char_traits<Char>::length(s)) {}
|
: data_(s), size_(std::char_traits<Char>::length(s)) {}
|
||||||
|
|
||||||
@ -381,11 +384,12 @@ template <typename Char> class basic_string_view {
|
|||||||
: data_(s.data()),
|
: data_(s.data()),
|
||||||
size_(s.size()) {}
|
size_(s.size()) {}
|
||||||
|
|
||||||
template <
|
#if __cplusplus >= 201703L // C++17's std::string_view::size() is constexpr.
|
||||||
typename S,
|
FMT_CONSTEXPR
|
||||||
FMT_ENABLE_IF(std::is_same<S, internal::std_string_view<Char>>::value)>
|
#endif
|
||||||
FMT_CONSTEXPR basic_string_view(S s) FMT_NOEXCEPT : data_(s.data()),
|
basic_string_view(internal::std_string_view<Char> s)
|
||||||
size_(s.size()) {}
|
FMT_NOEXCEPT : data_(s.data()),
|
||||||
|
size_(s.size()) {}
|
||||||
|
|
||||||
/** Returns a pointer to the string data. */
|
/** Returns a pointer to the string data. */
|
||||||
FMT_CONSTEXPR const Char* data() const { return data_; }
|
FMT_CONSTEXPR const Char* data() const { return data_; }
|
||||||
|
|||||||
@ -2236,6 +2236,7 @@ enum class arg_id_kind { none, index, name };
|
|||||||
// An argument reference.
|
// An argument reference.
|
||||||
template <typename Char> struct arg_ref {
|
template <typename Char> struct arg_ref {
|
||||||
FMT_CONSTEXPR arg_ref() : kind(arg_id_kind::none), val() {}
|
FMT_CONSTEXPR arg_ref() : kind(arg_id_kind::none), val() {}
|
||||||
|
|
||||||
FMT_CONSTEXPR explicit arg_ref(int index)
|
FMT_CONSTEXPR explicit arg_ref(int index)
|
||||||
: kind(arg_id_kind::index), val(index) {}
|
: kind(arg_id_kind::index), val(index) {}
|
||||||
FMT_CONSTEXPR explicit arg_ref(basic_string_view<Char> name)
|
FMT_CONSTEXPR explicit arg_ref(basic_string_view<Char> name)
|
||||||
@ -2266,8 +2267,8 @@ struct dynamic_format_specs : basic_format_specs<Char> {
|
|||||||
arg_ref<Char> precision_ref;
|
arg_ref<Char> precision_ref;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Format spec handler that saves references to arguments representing dynamic
|
// Format spec handler that saves references to arguments representing
|
||||||
// width and precision to be resolved at formatting time.
|
// dynamic width and precision to be resolved at formatting time.
|
||||||
template <typename ParseContext>
|
template <typename ParseContext>
|
||||||
class dynamic_specs_handler
|
class dynamic_specs_handler
|
||||||
: public specs_setter<typename ParseContext::char_type> {
|
: public specs_setter<typename ParseContext::char_type> {
|
||||||
@ -2579,8 +2580,9 @@ FMT_CONSTEXPR void parse_format_string(basic_string_view<Char> format_str,
|
|||||||
auto begin = format_str.data();
|
auto begin = format_str.data();
|
||||||
auto end = begin + format_str.size();
|
auto end = begin + format_str.size();
|
||||||
while (begin != end) {
|
while (begin != end) {
|
||||||
// Doing two passes with memchr (one for '{' and another for '}') is up to
|
// Doing two passes with memchr (one for '{' and another for '}') is up
|
||||||
// 2.5x faster than the naive one-pass implementation on big format strings.
|
// to 2.5x faster than the naive one-pass implementation on big format
|
||||||
|
// strings.
|
||||||
const Char* p = begin;
|
const Char* p = begin;
|
||||||
if (*begin != '{' && !find<IS_CONSTEXPR>(begin + 1, end, '{', p))
|
if (*begin != '{' && !find<IS_CONSTEXPR>(begin + 1, end, '{', p))
|
||||||
return write(begin, end);
|
return write(begin, end);
|
||||||
@ -3523,9 +3525,22 @@ template <typename Char> struct udl_arg {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Converts string literals to basic_string_view.
|
||||||
template <typename Char, size_t N>
|
template <typename Char, size_t N>
|
||||||
FMT_CONSTEXPR basic_string_view<Char> literal_to_view(const Char (&s)[N]) {
|
FMT_CONSTEXPR basic_string_view<Char> compile_string_to_view(
|
||||||
return {s, N - 1};
|
const Char (&s)[N]) {
|
||||||
|
// Remove trailing null character if needed. Won't be present if this is used
|
||||||
|
// with raw character array (i.e. not defined as a string).
|
||||||
|
return {s, N - ((N > 0 && std::char_traits<Char>::to_int_type(s[N - 1]) == 0)
|
||||||
|
? 1
|
||||||
|
: 0)};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts string_view to basic_string_view.
|
||||||
|
template <typename Char>
|
||||||
|
FMT_CONSTEXPR basic_string_view<Char> compile_string_to_view(
|
||||||
|
const std_string_view<Char>& s) {
|
||||||
|
return {s.data(), s.size()};
|
||||||
}
|
}
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
@ -3583,18 +3598,17 @@ FMT_CONSTEXPR internal::udl_arg<wchar_t> operator"" _a(const wchar_t* s,
|
|||||||
#endif // FMT_USE_USER_DEFINED_LITERALS
|
#endif // FMT_USE_USER_DEFINED_LITERALS
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
#define FMT_STRING_IMPL(s, ...) \
|
#define FMT_STRING_IMPL(s, ...) \
|
||||||
[] { \
|
[] { \
|
||||||
/* Use a macro-like name to avoid shadowing warnings. */ \
|
/* Use a macro-like name to avoid shadowing warnings. */ \
|
||||||
struct FMT_COMPILE_STRING : fmt::compile_string { \
|
struct FMT_COMPILE_STRING : fmt::compile_string { \
|
||||||
using char_type = fmt::remove_cvref_t<decltype(*s)>; \
|
using char_type = fmt::remove_cvref_t<decltype(s[0])>; \
|
||||||
FMT_MAYBE_UNUSED __VA_ARGS__ FMT_CONSTEXPR \
|
FMT_MAYBE_UNUSED __VA_ARGS__ FMT_CONSTEXPR \
|
||||||
operator fmt::basic_string_view<char_type>() const { \
|
operator fmt::basic_string_view<char_type>() const { \
|
||||||
/* FMT_STRING only accepts string literals. */ \
|
return fmt::internal::compile_string_to_view<char_type>(s); \
|
||||||
return fmt::internal::literal_to_view(s); \
|
} \
|
||||||
} \
|
}; \
|
||||||
}; \
|
return FMT_COMPILE_STRING(); \
|
||||||
return FMT_COMPILE_STRING(); \
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -46,6 +46,7 @@ using fmt::format_error;
|
|||||||
using fmt::memory_buffer;
|
using fmt::memory_buffer;
|
||||||
using fmt::string_view;
|
using fmt::string_view;
|
||||||
using fmt::wmemory_buffer;
|
using fmt::wmemory_buffer;
|
||||||
|
using fmt::wstring_view;
|
||||||
using fmt::internal::basic_writer;
|
using fmt::internal::basic_writer;
|
||||||
using fmt::internal::max_value;
|
using fmt::internal::max_value;
|
||||||
|
|
||||||
@ -1853,10 +1854,25 @@ TEST(FormatTest, UnpackedArgs) {
|
|||||||
struct string_like {};
|
struct string_like {};
|
||||||
fmt::string_view to_string_view(string_like) { return "foo"; }
|
fmt::string_view to_string_view(string_like) { return "foo"; }
|
||||||
|
|
||||||
|
#if __cplusplus >= 201703L
|
||||||
|
namespace {
|
||||||
|
FMT_CONSTEXPR char withNull[3] = {'{', '}', '\0'};
|
||||||
|
FMT_CONSTEXPR char noNull[2] = {'{', '}'};
|
||||||
|
} // namespace
|
||||||
|
#endif
|
||||||
|
|
||||||
TEST(FormatTest, CompileTimeString) {
|
TEST(FormatTest, CompileTimeString) {
|
||||||
EXPECT_EQ("42", fmt::format(FMT_STRING("{}"), 42));
|
EXPECT_EQ("42", fmt::format(FMT_STRING("{}"), 42));
|
||||||
EXPECT_EQ(L"42", fmt::format(FMT_STRING(L"{}"), 42));
|
EXPECT_EQ(L"42", fmt::format(FMT_STRING(L"{}"), 42));
|
||||||
EXPECT_EQ("foo", fmt::format(FMT_STRING("{}"), string_like()));
|
EXPECT_EQ("foo", fmt::format(FMT_STRING("{}"), string_like()));
|
||||||
|
#if __cplusplus >= 201703L
|
||||||
|
EXPECT_EQ("42", fmt::format(FMT_STRING(withNull), 42));
|
||||||
|
EXPECT_EQ("42", fmt::format(FMT_STRING(noNull), 42));
|
||||||
|
#endif
|
||||||
|
#if defined(FMT_USE_STRING_VIEW) && __cplusplus >= 201703L
|
||||||
|
EXPECT_EQ("42", fmt::format(FMT_STRING(std::string_view("{}")), 42));
|
||||||
|
EXPECT_EQ(L"42", fmt::format(FMT_STRING(std::wstring_view(L"{}")), 42));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatTest, CustomFormatCompileTimeString) {
|
TEST(FormatTest, CustomFormatCompileTimeString) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user