Cleanup string traits
This commit is contained in:
parent
1e938dda20
commit
0641b844ac
@ -413,17 +413,17 @@ FMT_CONSTEXPR auto to_unsigned(Int value) ->
|
||||
}
|
||||
|
||||
// A heuristic to detect std::string and std::[experimental::]string_view.
|
||||
// It is mainly used to avoid dependency on <[experimental/]string_view>.
|
||||
template <typename T, typename Enable = void>
|
||||
struct is_string_like : std::false_type {};
|
||||
struct is_std_string_like : std::false_type {};
|
||||
template <typename T>
|
||||
struct is_string_like<T, void_t<decltype(std::declval<T>().find_first_of(
|
||||
typename T::value_type(), 0))>> : std::true_type {
|
||||
};
|
||||
struct is_std_string_like<T, void_t<decltype(std::declval<T>().find_first_of(
|
||||
typename T::value_type(), 0))>>
|
||||
: std::true_type {};
|
||||
|
||||
FMT_CONSTEXPR inline auto is_utf8() -> bool {
|
||||
FMT_MSC_WARNING(suppress : 4566) constexpr unsigned char section[] = "\u00A7";
|
||||
|
||||
// Avoid buggy sign extensions in MSVC's constant evaluation mode (#2297).
|
||||
// Avoid an MSVC sign extension bug: https://github.com/fmtlib/fmt/pull/2297.
|
||||
using uchar = unsigned char;
|
||||
return FMT_UNICODE || (sizeof(section) == 3 && uchar(section[0]) == 0xC2 &&
|
||||
uchar(section[1]) == 0xA7);
|
||||
@ -495,7 +495,7 @@ template <typename Char> class basic_string_view {
|
||||
``std::basic_string_view`` object.
|
||||
*/
|
||||
template <typename S,
|
||||
FMT_ENABLE_IF(detail::is_string_like<S>::value&& std::is_same<
|
||||
FMT_ENABLE_IF(detail::is_std_string_like<S>::value&& std::is_same<
|
||||
typename S::value_type, Char>::value)>
|
||||
FMT_CONSTEXPR basic_string_view(const S& s) noexcept
|
||||
: data_(s.data()), size_(s.size()) {}
|
||||
@ -576,9 +576,9 @@ template <typename Char, FMT_ENABLE_IF(is_char<Char>::value)>
|
||||
FMT_INLINE auto to_string_view(const Char* s) -> basic_string_view<Char> {
|
||||
return s;
|
||||
}
|
||||
template <typename S, FMT_ENABLE_IF(is_string_like<S>::value)>
|
||||
inline auto to_string_view(const S& s)
|
||||
-> basic_string_view<typename S::value_type> {
|
||||
template <typename T, FMT_ENABLE_IF(is_std_string_like<T>::value)>
|
||||
inline auto to_string_view(const T& s)
|
||||
-> basic_string_view<typename T::value_type> {
|
||||
return s;
|
||||
}
|
||||
template <typename Char>
|
||||
@ -586,15 +586,14 @@ constexpr auto to_string_view(basic_string_view<Char> s)
|
||||
-> basic_string_view<Char> {
|
||||
return s;
|
||||
}
|
||||
void to_string_view(...);
|
||||
|
||||
// Specifies whether S is a string type convertible to fmt::basic_string_view.
|
||||
// It should be a constexpr function but MSVC 2017 fails to compile it in
|
||||
// enable_if and MSVC 2015 fails to compile it as an alias template.
|
||||
// ADL is intentionally disabled as to_string_view is not an extension point.
|
||||
template <typename S, typename = void>
|
||||
struct is_string
|
||||
: std::is_class<decltype(detail::to_string_view(std::declval<S>()))> {};
|
||||
template <typename T, typename Enable = void>
|
||||
struct has_to_string_view : std::false_type {};
|
||||
// detail:: is intentional since to_string_view is not an extension point.
|
||||
template <typename T>
|
||||
struct has_to_string_view<
|
||||
T, void_t<decltype(detail::to_string_view(std::declval<T>()))>>
|
||||
: std::true_type {};
|
||||
|
||||
enum class type {
|
||||
none_type,
|
||||
@ -1482,7 +1481,7 @@ template <typename Context> struct arg_mapper {
|
||||
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) &&
|
||||
!is_string<U>::value && !is_char<U>::value &&
|
||||
!has_to_string_view<U>::value && !is_char<U>::value &&
|
||||
!is_named_arg<U>::value &&
|
||||
!std::is_arithmetic<format_as_t<U>>::value)>
|
||||
FMT_CONSTEXPR FMT_INLINE auto map(T& val)
|
||||
|
@ -3733,7 +3733,7 @@ FMT_CONSTEXPR auto write(OutputIt out, basic_string_view<Char> value)
|
||||
}
|
||||
|
||||
template <typename Char, typename OutputIt, typename T,
|
||||
FMT_ENABLE_IF(is_string<T>::value)>
|
||||
FMT_ENABLE_IF(has_to_string_view<T>::value)>
|
||||
constexpr auto write(OutputIt out, const T& value) -> OutputIt {
|
||||
return write<Char>(out, to_string_view(value));
|
||||
}
|
||||
@ -3786,7 +3786,7 @@ auto write(OutputIt out, const T* value, const format_specs<Char>& specs = {},
|
||||
template <typename Char, typename OutputIt, typename T,
|
||||
typename Context = basic_format_context<OutputIt, Char>>
|
||||
FMT_CONSTEXPR auto write(OutputIt out, const T& value) -> enable_if_t<
|
||||
std::is_class<T>::value && !is_string<T>::value &&
|
||||
std::is_class<T>::value && !has_to_string_view<T>::value &&
|
||||
!is_floating_point<T>::value && !std::is_same<T, Char>::value &&
|
||||
!std::is_same<T, remove_cvref_t<decltype(arg_mapper<Context>().map(
|
||||
value))>>::value,
|
||||
|
@ -605,8 +605,7 @@ inline auto vsprintf(
|
||||
std::string message = fmt::sprintf("The answer is %d", 42);
|
||||
\endrst
|
||||
*/
|
||||
template <typename S, typename... T,
|
||||
typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
|
||||
template <typename S, typename... T, typename Char = char_t<S>>
|
||||
inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string<Char> {
|
||||
return vsprintf(detail::to_string_view(fmt),
|
||||
fmt::make_format_args<basic_printf_context<Char>>(args...));
|
||||
|
@ -41,23 +41,6 @@ template <typename OutputIt> auto copy(wchar_t ch, OutputIt out) -> OutputIt {
|
||||
return out;
|
||||
}
|
||||
|
||||
// Returns true if T has a std::string-like interface, like std::string_view.
|
||||
template <typename T> class is_std_string_like {
|
||||
template <typename U>
|
||||
static auto check(U* p)
|
||||
-> decltype((void)p->find('a'), p->length(), (void)p->data(), int());
|
||||
template <typename> static void check(...);
|
||||
|
||||
public:
|
||||
static constexpr const bool value =
|
||||
is_string<T>::value ||
|
||||
std::is_convertible<T, std_string_view<char>>::value ||
|
||||
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
struct is_std_string_like<fmt::basic_string_view<Char>> : std::true_type {};
|
||||
|
||||
template <typename T> class is_map {
|
||||
template <typename U> static auto check(U*) -> typename U::mapped_type;
|
||||
template <typename> static void check(...);
|
||||
@ -377,7 +360,8 @@ struct formatter<Tuple, Char,
|
||||
|
||||
template <typename T, typename Char> struct is_range {
|
||||
static constexpr const bool value =
|
||||
detail::is_range_<T>::value && !detail::is_std_string_like<T>::value &&
|
||||
detail::is_range_<T>::value &&
|
||||
!detail::has_to_string_view<T>::value &&
|
||||
!std::is_convertible<T, std::basic_string<Char>>::value &&
|
||||
!std::is_convertible<T, detail::std_string_view<Char>>::value;
|
||||
};
|
||||
|
@ -293,7 +293,7 @@ template <typename T, typename C> class is_variant_formattable_ {
|
||||
|
||||
template <typename Char, typename OutputIt, typename T>
|
||||
auto write_variant_alternative(OutputIt out, const T& v) -> OutputIt {
|
||||
if constexpr (is_string<T>::value)
|
||||
if constexpr (has_to_string_view<T>::value)
|
||||
return write_escaped_string<Char>(out, detail::to_string_view(v));
|
||||
else if constexpr (std::is_same_v<T, Char>)
|
||||
return write_escaped_char(out, v);
|
||||
|
@ -32,27 +32,27 @@ using testing::Contains;
|
||||
|
||||
struct non_string {};
|
||||
|
||||
template <typename T> class is_string_test : public testing::Test {};
|
||||
template <typename T> class has_to_string_view_test : public testing::Test {};
|
||||
|
||||
using string_char_types = testing::Types<char, wchar_t, char16_t, char32_t>;
|
||||
TYPED_TEST_SUITE(is_string_test, string_char_types);
|
||||
TYPED_TEST_SUITE(has_to_string_view_test, string_char_types);
|
||||
|
||||
template <typename Char>
|
||||
struct derived_from_string_view : fmt::basic_string_view<Char> {};
|
||||
|
||||
TYPED_TEST(is_string_test, is_string) {
|
||||
EXPECT_TRUE(fmt::detail::is_string<TypeParam*>::value);
|
||||
EXPECT_TRUE(fmt::detail::is_string<const TypeParam*>::value);
|
||||
EXPECT_TRUE(fmt::detail::is_string<TypeParam[2]>::value);
|
||||
EXPECT_TRUE(fmt::detail::is_string<const TypeParam[2]>::value);
|
||||
EXPECT_TRUE(fmt::detail::is_string<std::basic_string<TypeParam>>::value);
|
||||
EXPECT_TRUE(fmt::detail::is_string<fmt::basic_string_view<TypeParam>>::value);
|
||||
TYPED_TEST(has_to_string_view_test, has_to_string_view) {
|
||||
EXPECT_TRUE(fmt::detail::has_to_string_view<TypeParam*>::value);
|
||||
EXPECT_TRUE(fmt::detail::has_to_string_view<const TypeParam*>::value);
|
||||
EXPECT_TRUE(fmt::detail::has_to_string_view<TypeParam[2]>::value);
|
||||
EXPECT_TRUE(fmt::detail::has_to_string_view<const TypeParam[2]>::value);
|
||||
EXPECT_TRUE(fmt::detail::has_to_string_view<std::basic_string<TypeParam>>::value);
|
||||
EXPECT_TRUE(fmt::detail::has_to_string_view<fmt::basic_string_view<TypeParam>>::value);
|
||||
EXPECT_TRUE(
|
||||
fmt::detail::is_string<derived_from_string_view<TypeParam>>::value);
|
||||
fmt::detail::has_to_string_view<derived_from_string_view<TypeParam>>::value);
|
||||
using fmt_string_view = fmt::detail::std_string_view<TypeParam>;
|
||||
EXPECT_TRUE(std::is_empty<fmt_string_view>::value !=
|
||||
fmt::detail::is_string<fmt_string_view>::value);
|
||||
EXPECT_FALSE(fmt::detail::is_string<non_string>::value);
|
||||
fmt::detail::has_to_string_view<fmt_string_view>::value);
|
||||
EXPECT_FALSE(fmt::detail::has_to_string_view<non_string>::value);
|
||||
}
|
||||
|
||||
// std::is_constructible is broken in MSVC until version 2015.
|
||||
|
Loading…
Reference in New Issue
Block a user