mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-30 10:47:35 +02:00
Cleanup type mapping
This commit is contained in:
@ -1100,6 +1100,13 @@ struct use_format_as<
|
|||||||
T, bool_constant<std::is_integral<format_as_result<T>>::value>>
|
T, bool_constant<std::is_integral<format_as_result<T>>::value>>
|
||||||
: std::true_type {};
|
: std::true_type {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using use_formatter =
|
||||||
|
bool_constant<(std::is_class<T>::value || std::is_enum<T>::value ||
|
||||||
|
std::is_union<T>::value) &&
|
||||||
|
!has_to_string_view<T>::value && !is_named_arg<T>::value &&
|
||||||
|
!use_format_as<T>::value>;
|
||||||
|
|
||||||
template <typename Char, typename T>
|
template <typename Char, typename T>
|
||||||
constexpr auto has_const_formatter_impl(T*)
|
constexpr auto has_const_formatter_impl(T*)
|
||||||
-> decltype(formatter<T, Char>().format(
|
-> decltype(formatter<T, Char>().format(
|
||||||
@ -1117,11 +1124,9 @@ constexpr auto has_const_formatter() -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct unformattable {};
|
struct unformattable {};
|
||||||
struct unformattable_char : unformattable {};
|
|
||||||
struct unformattable_pointer : unformattable {};
|
|
||||||
|
|
||||||
// Maps formatting argument types to reduce the set of types we need to work
|
// Maps formatting argument types to a smaller set. Returns unformattable* on
|
||||||
// with. Returns unformattable* on errors to be SFINAE-friendly.
|
// errors to be SFINAE-friendly.
|
||||||
template <typename Char> struct arg_mapper {
|
template <typename Char> struct arg_mapper {
|
||||||
static auto map(signed char) -> int;
|
static auto map(signed char) -> int;
|
||||||
static auto map(unsigned char) -> unsigned;
|
static auto map(unsigned char) -> unsigned;
|
||||||
@ -1147,7 +1152,7 @@ template <typename Char> struct arg_mapper {
|
|||||||
template <typename T, FMT_ENABLE_IF(is_char<T>::value)>
|
template <typename T, FMT_ENABLE_IF(is_char<T>::value)>
|
||||||
static auto map(T) -> conditional_t<std::is_same<T, char>::value ||
|
static auto map(T) -> conditional_t<std::is_same<T, char>::value ||
|
||||||
std::is_same<T, Char>::value,
|
std::is_same<T, Char>::value,
|
||||||
Char, unformattable_char>;
|
Char, unformattable>;
|
||||||
|
|
||||||
static auto map(float) -> float;
|
static auto map(float) -> float;
|
||||||
static auto map(double) -> double;
|
static auto map(double) -> double;
|
||||||
@ -1159,7 +1164,7 @@ template <typename Char> struct arg_mapper {
|
|||||||
FMT_ENABLE_IF(!std::is_pointer<T>::value)>
|
FMT_ENABLE_IF(!std::is_pointer<T>::value)>
|
||||||
static auto map(const T&)
|
static auto map(const T&)
|
||||||
-> conditional_t<std::is_same<C, Char>::value, basic_string_view<C>,
|
-> conditional_t<std::is_same<C, Char>::value, basic_string_view<C>,
|
||||||
unformattable_char>;
|
unformattable>;
|
||||||
|
|
||||||
static auto map(void*) -> const void*;
|
static auto map(void*) -> const void*;
|
||||||
static auto map(const void*) -> const void*;
|
static auto map(const void*) -> const void*;
|
||||||
@ -1168,7 +1173,7 @@ template <typename Char> struct arg_mapper {
|
|||||||
static auto map(std::nullptr_t) -> const void*;
|
static auto map(std::nullptr_t) -> const void*;
|
||||||
template <typename T, FMT_ENABLE_IF(std::is_pointer<T>::value ||
|
template <typename T, FMT_ENABLE_IF(std::is_pointer<T>::value ||
|
||||||
std::is_member_pointer<T>::value)>
|
std::is_member_pointer<T>::value)>
|
||||||
static auto map(const T&) -> unformattable_pointer;
|
static auto map(const T&) -> unformattable;
|
||||||
|
|
||||||
template <typename T, std::size_t N, FMT_ENABLE_IF(!is_char<T>::value)>
|
template <typename T, std::size_t N, FMT_ENABLE_IF(!is_char<T>::value)>
|
||||||
static auto map(const T (&)[N]) -> const T (&)[N];
|
static auto map(const T (&)[N]) -> const T (&)[N];
|
||||||
@ -1182,25 +1187,12 @@ template <typename Char> struct arg_mapper {
|
|||||||
(std::is_constructible<formatter<U, Char>>::value &&
|
(std::is_constructible<formatter<U, Char>>::value &&
|
||||||
!std::is_const<T>::value)> {};
|
!std::is_const<T>::value)> {};
|
||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(formattable<T>::value)>
|
template <typename T, FMT_ENABLE_IF(use_formatter<remove_const_t<T>>::value)>
|
||||||
static auto do_map(T& x) -> T&;
|
static auto map(T&)
|
||||||
template <typename T, FMT_ENABLE_IF(!formattable<T>::value)>
|
-> conditional_t<formattable<T>::value, T&, unformattable>;
|
||||||
static auto do_map(T&) -> unformattable;
|
|
||||||
|
|
||||||
// is_fundamental is used to allow formatters for extended FP types.
|
|
||||||
template <typename T, typename U = remove_const_t<T>,
|
|
||||||
FMT_ENABLE_IF(
|
|
||||||
(std::is_class<U>::value || std::is_enum<U>::value ||
|
|
||||||
std::is_union<U>::value || std::is_fundamental<U>::value) &&
|
|
||||||
!has_to_string_view<U>::value && !is_char<U>::value &&
|
|
||||||
!is_named_arg<U>::value && !std::is_integral<U>::value &&
|
|
||||||
!use_format_as<U>::value)>
|
|
||||||
static auto map(T& x) -> decltype(do_map(x));
|
|
||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(is_named_arg<T>::value)>
|
template <typename T, FMT_ENABLE_IF(is_named_arg<T>::value)>
|
||||||
static auto map(const T& named_arg) -> decltype(map(named_arg.value));
|
static auto map(const T& named_arg) -> decltype(map(named_arg.value));
|
||||||
|
|
||||||
static auto map(...) -> unformattable;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// detail:: is used to workaround a bug in MSVC 2017.
|
// detail:: is used to workaround a bug in MSVC 2017.
|
||||||
@ -2183,6 +2175,9 @@ template <typename Context> class value {
|
|||||||
template <typename T, FMT_ENABLE_IF(std::is_pointer<T>::value ||
|
template <typename T, FMT_ENABLE_IF(std::is_pointer<T>::value ||
|
||||||
std::is_member_pointer<T>::value)>
|
std::is_member_pointer<T>::value)>
|
||||||
value(const T&) {
|
value(const T&) {
|
||||||
|
// Formatting of arbitrary pointers is disallowed. If you want to format a
|
||||||
|
// pointer cast it to `void*` or `const void*`. In particular, this forbids
|
||||||
|
// formatting of `[const] volatile char*` printed as bool by iostreams.
|
||||||
static_assert(sizeof(T) == 0,
|
static_assert(sizeof(T) == 0,
|
||||||
"formatting of non-void pointers is disallowed");
|
"formatting of non-void pointers is disallowed");
|
||||||
}
|
}
|
||||||
@ -2196,16 +2191,7 @@ template <typename Context> class value {
|
|||||||
template <typename T, FMT_ENABLE_IF(is_named_arg<T>::value)>
|
template <typename T, FMT_ENABLE_IF(is_named_arg<T>::value)>
|
||||||
value(const T& named_arg) : value(named_arg.value) {}
|
value(const T& named_arg) : value(named_arg.value) {}
|
||||||
|
|
||||||
template <typename T, typename U = remove_cvref_t<T>>
|
template <typename T, FMT_ENABLE_IF(use_formatter<remove_cvref_t<T>>::value)>
|
||||||
using mappable =
|
|
||||||
bool_constant<!std::is_fundamental<U>::value &&
|
|
||||||
!std::is_pointer<U>::value && !is_named_arg<U>::value &&
|
|
||||||
!use_format_as<U>::value>;
|
|
||||||
|
|
||||||
template <
|
|
||||||
typename T,
|
|
||||||
typename M = decltype(arg_mapper<char_type>::map(std::declval<T&>())),
|
|
||||||
FMT_ENABLE_IF(std::is_same<T, M>::value&& mappable<T>::value)>
|
|
||||||
FMT_CONSTEXPR20 FMT_INLINE value(T&& x) : value(x, custom_tag()) {}
|
FMT_CONSTEXPR20 FMT_INLINE value(T&& x) : value(x, custom_tag()) {}
|
||||||
|
|
||||||
FMT_ALWAYS_INLINE value(const named_arg_info<char_type>* args, size_t size)
|
FMT_ALWAYS_INLINE value(const named_arg_info<char_type>* args, size_t size)
|
||||||
@ -2213,15 +2199,6 @@ template <typename Context> class value {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename T> FMT_CONSTEXPR value(const T& x, custom_tag) {
|
template <typename T> FMT_CONSTEXPR value(const T& x, custom_tag) {
|
||||||
// Formatting of arbitrary pointers is disallowed. If you want to format a
|
|
||||||
// pointer cast it to `void*` or `const void*`. In particular, this forbids
|
|
||||||
// formatting of `[const] volatile char*` printed as bool by iostreams.
|
|
||||||
enum {
|
|
||||||
formattable_pointer = !std::is_same<T, unformattable_pointer>::value
|
|
||||||
};
|
|
||||||
static_assert(formattable_pointer,
|
|
||||||
"formatting of non-void pointers is disallowed");
|
|
||||||
|
|
||||||
using value_type = remove_cvref_t<T>;
|
using value_type = remove_cvref_t<T>;
|
||||||
enum { formattable = !std::is_same<T, unformattable>::value };
|
enum { formattable = !std::is_same<T, unformattable>::value };
|
||||||
|
|
||||||
@ -2242,10 +2219,6 @@ template <typename Context> class value {
|
|||||||
if (!is_constant_evaluated())
|
if (!is_constant_evaluated())
|
||||||
custom.value =
|
custom.value =
|
||||||
const_cast<char*>(&reinterpret_cast<const volatile char&>(x));
|
const_cast<char*>(&reinterpret_cast<const volatile char&>(x));
|
||||||
// Get the formatter type through the context to allow different contexts
|
|
||||||
// have different extension points, e.g. `formatter<T>` for `format` and
|
|
||||||
// `printf_formatter<T>` for `printf`.
|
|
||||||
|
|
||||||
custom.format = format_custom<value_type, formatter<value_type, char_type>>;
|
custom.format = format_custom<value_type, formatter<value_type, char_type>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user