Support compile-time strings and compile-time format string compilation in module
Make just the necessary parts available for lookup from client context.
This commit is contained in:
parent
3423d75475
commit
0193e7c428
@ -164,7 +164,8 @@ struct is_compiled_string : std::is_base_of<compiled_string, S> {};
|
||||
#endif
|
||||
|
||||
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
||||
template <typename Char, size_t N, fixed_string<Char, N> Str>
|
||||
template <typename Char, size_t N,
|
||||
fmt::detail_exported::fixed_string<Char, N> Str>
|
||||
struct udl_compiled_string : compiled_string {
|
||||
using char_type = Char;
|
||||
constexpr operator basic_string_view<char_type>() const {
|
||||
@ -622,7 +623,7 @@ void print(const S& format_str, const Args&... args) {
|
||||
|
||||
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
||||
inline namespace literals {
|
||||
template <detail::fixed_string Str>
|
||||
template <detail_exported::fixed_string Str>
|
||||
constexpr detail::udl_compiled_string<
|
||||
remove_cvref_t<decltype(Str.data[0])>,
|
||||
sizeof(Str.data) / sizeof(decltype(Str.data[0])), Str>
|
||||
|
@ -778,6 +778,33 @@ FMT_INLINE auto make_args_checked(const S& fmt,
|
||||
return {args...};
|
||||
}
|
||||
|
||||
// compile-time support
|
||||
namespace detail_exported {
|
||||
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
||||
template <typename Char, size_t N> struct fixed_string {
|
||||
constexpr fixed_string(const Char (&str)[N]) {
|
||||
detail::copy_str<Char, const Char*, Char*>(static_cast<const Char*>(str),
|
||||
str + N, data);
|
||||
}
|
||||
Char data[N]{};
|
||||
};
|
||||
#endif
|
||||
|
||||
// Converts a compile-time string to basic_string_view.
|
||||
template <typename Char, size_t N>
|
||||
constexpr auto compile_string_to_view(const Char (&s)[N])
|
||||
-> basic_string_view<Char> {
|
||||
// Remove trailing NUL character if needed. Won't be present if this is used
|
||||
// with a raw character array (i.e. not defined as a string).
|
||||
return {s, N - (std::char_traits<Char>::to_int_type(s[N - 1]) == 0 ? 1 : 0)};
|
||||
}
|
||||
template <typename Char>
|
||||
constexpr auto compile_string_to_view(detail::std_string_view<Char> s)
|
||||
-> basic_string_view<Char> {
|
||||
return {s.data(), s.size()};
|
||||
}
|
||||
} // namespace detail_exported
|
||||
|
||||
FMT_BEGIN_DETAIL_NAMESPACE
|
||||
|
||||
inline void throw_format_error(const char* message) {
|
||||
@ -2098,20 +2125,6 @@ FMT_CONSTEXPR void handle_dynamic_spec(int& value,
|
||||
}
|
||||
}
|
||||
|
||||
// Converts a compile-time string to basic_string_view.
|
||||
template <typename Char, size_t N>
|
||||
constexpr auto compile_string_to_view(const Char (&s)[N])
|
||||
-> basic_string_view<Char> {
|
||||
// Remove trailing NUL character if needed. Won't be present if this is used
|
||||
// with a raw character array (i.e. not defined as a string).
|
||||
return {s, N - (std::char_traits<Char>::to_int_type(s[N - 1]) == 0 ? 1 : 0)};
|
||||
}
|
||||
template <typename Char>
|
||||
constexpr auto compile_string_to_view(std_string_view<Char> s)
|
||||
-> basic_string_view<Char> {
|
||||
return {s.data(), s.size()};
|
||||
}
|
||||
|
||||
#define FMT_STRING_IMPL(s, base, explicit) \
|
||||
[] { \
|
||||
/* Use the hidden visibility as a workaround for a GCC bug (#1973). */ \
|
||||
@ -2120,7 +2133,7 @@ constexpr auto compile_string_to_view(std_string_view<Char> s)
|
||||
using char_type = fmt::remove_cvref_t<decltype(s[0])>; \
|
||||
FMT_MAYBE_UNUSED FMT_CONSTEXPR explicit \
|
||||
operator fmt::basic_string_view<char_type>() const { \
|
||||
return fmt::detail::compile_string_to_view<char_type>(s); \
|
||||
return fmt::detail_exported::compile_string_to_view<char_type>(s); \
|
||||
} \
|
||||
}; \
|
||||
return FMT_COMPILE_STRING(); \
|
||||
@ -2138,16 +2151,6 @@ constexpr auto compile_string_to_view(std_string_view<Char> s)
|
||||
*/
|
||||
#define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::compile_string, )
|
||||
|
||||
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
||||
template <typename Char, size_t N> struct fixed_string {
|
||||
constexpr fixed_string(const Char (&str)[N]) {
|
||||
copy_str<Char, const Char*, Char*>(static_cast<const Char*>(str), str + N,
|
||||
data);
|
||||
}
|
||||
Char data[N]{};
|
||||
};
|
||||
#endif
|
||||
|
||||
#if FMT_USE_USER_DEFINED_LITERALS
|
||||
template <typename Char> struct udl_formatter {
|
||||
basic_string_view<Char> str;
|
||||
@ -2159,7 +2162,8 @@ template <typename Char> struct udl_formatter {
|
||||
};
|
||||
|
||||
# if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
||||
template <typename T, typename Char, size_t N, fixed_string<Char, N> Str>
|
||||
template <typename T, typename Char, size_t N,
|
||||
fmt::detail_exported::fixed_string<Char, N> Str>
|
||||
struct statically_named_arg : view {
|
||||
static constexpr auto name = Str.data;
|
||||
|
||||
@ -2167,14 +2171,18 @@ struct statically_named_arg : view {
|
||||
statically_named_arg(const T& v) : value(v) {}
|
||||
};
|
||||
|
||||
template <typename T, typename Char, size_t N, fixed_string<Char, N> Str>
|
||||
template <typename T, typename Char, size_t N,
|
||||
fmt::detail_exported::fixed_string<Char, N> Str>
|
||||
struct is_named_arg<statically_named_arg<T, Char, N, Str>> : std::true_type {};
|
||||
|
||||
template <typename T, typename Char, size_t N, fixed_string<Char, N> Str>
|
||||
template <typename T, typename Char, size_t N,
|
||||
fmt::detail_exported::fixed_string<Char, N> Str>
|
||||
struct is_statically_named_arg<statically_named_arg<T, Char, N, Str>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename Char, size_t N, fixed_string<Char, N> Str> struct udl_arg {
|
||||
template <typename Char, size_t N,
|
||||
fmt::detail_exported::fixed_string<Char, N> Str>
|
||||
struct udl_arg {
|
||||
template <typename T> auto operator=(T&& value) const {
|
||||
return statically_named_arg<T, Char, N, Str>(std::forward<T>(value));
|
||||
}
|
||||
@ -2721,7 +2729,7 @@ inline namespace literals {
|
||||
\endrst
|
||||
*/
|
||||
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
||||
template <detail::fixed_string Str>
|
||||
template <detail_exported::fixed_string Str>
|
||||
constexpr auto operator""_a()
|
||||
-> detail::udl_arg<remove_cvref_t<decltype(Str.data[0])>,
|
||||
sizeof(Str.data) / sizeof(decltype(Str.data[0])), Str> {
|
||||
|
@ -1,4 +1,8 @@
|
||||
module;
|
||||
#ifndef __cpp_modules
|
||||
# error Module not supported.
|
||||
#endif
|
||||
|
||||
// put all implementation-provided headers into the global module fragment
|
||||
// to prevent attachment to this module
|
||||
#if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER)
|
||||
@ -76,10 +80,6 @@ export module fmt;
|
||||
} \
|
||||
export {
|
||||
|
||||
#if defined(_MSC_FULL_VER) && _MSC_FULL_VER > 192930036
|
||||
#define FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 0
|
||||
#endif
|
||||
|
||||
// all library-provided declarations and definitions
|
||||
// must be in the module purview to be exported
|
||||
#include "fmt/args.h"
|
||||
|
@ -445,3 +445,11 @@ TEST(module_test, has_formatter) {
|
||||
TEST(module_test, is_formattable) {
|
||||
EXPECT_FALSE(fmt::is_formattable<disabled_formatter>::value);
|
||||
}
|
||||
|
||||
TEST(module_test, compile_format_string) {
|
||||
using namespace fmt::literals;
|
||||
EXPECT_EQ("42", fmt::format("{0:x}"_cf, 0x42));
|
||||
EXPECT_EQ(L"42", fmt::format(L"{:}"_cf, 42));
|
||||
EXPECT_EQ("4.2", fmt::format("{arg:3.1f}"_cf, "arg"_a = 4.2));
|
||||
EXPECT_EQ(L" 42", fmt::format(L"{arg:>3}"_cf, L"arg"_a = L"42"));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user