diff --git a/include/fmt/base.h b/include/fmt/base.h index ef815276..9a51cf5a 100644 --- a/include/fmt/base.h +++ b/include/fmt/base.h @@ -2226,17 +2226,39 @@ template class value { constexpr FMT_INLINE value() : no_value() {} constexpr FMT_INLINE value(int val) : int_value(val) {} constexpr FMT_INLINE value(unsigned val FMT_BUILTIN) : uint_value(val) {} + FMT_CONSTEXPR FMT_INLINE value(long val FMT_BUILTIN) { + if (sizeof(long) == sizeof(int)) + int_value = static_cast(val); + else + long_long_value = val; + } + FMT_CONSTEXPR FMT_INLINE value(unsigned long val FMT_BUILTIN) { + if (sizeof(long) == sizeof(int)) + uint_value = static_cast(val); + else + ulong_long_value = val; + } constexpr FMT_INLINE value(long long val FMT_BUILTIN) : long_long_value(val) {} constexpr FMT_INLINE value(unsigned long long val FMT_BUILTIN) : ulong_long_value(val) {} + template + constexpr FMT_INLINE value(bitint val FMT_BUILTIN) + : long_long_value(val) {} + template + constexpr FMT_INLINE value(ubitint val FMT_BUILTIN) + : ulong_long_value(val) {} FMT_INLINE value(int128_opt val FMT_BUILTIN) : int128_value(val) {} FMT_INLINE value(uint128_opt val FMT_BUILTIN) : uint128_value(val) {} constexpr FMT_INLINE value(float val FMT_BUILTIN) : float_value(val) {} constexpr FMT_INLINE value(double val FMT_BUILTIN) : double_value(val) {} FMT_INLINE value(long double val FMT_BUILTIN) : long_double_value(val) {} constexpr FMT_INLINE value(bool val FMT_BUILTIN) : bool_value(val) {} - constexpr FMT_INLINE value(char_type val FMT_BUILTIN) : char_value(val) {} + template ::value)> + constexpr FMT_INLINE value(T val FMT_BUILTIN) : char_value(val) { + static_assert(std::is_same::value, + "mixing character types is disallowed"); + } FMT_CONSTEXPR FMT_INLINE value(const char_type* val FMT_BUILTIN) { string.data = val; if (is_constant_evaluated()) string.size = {}; @@ -2248,16 +2270,20 @@ template class value { FMT_INLINE value(const void* val FMT_BUILTIN) : pointer(val) {} // We can't use mapped_t because of a bug in MSVC 2017. - template ::map( - std::declval()))>::value)> + template < + typename T, + typename M = decltype(arg_mapper::map(std::declval())), + FMT_ENABLE_IF(!std::is_same::value && + !std::is_integral>::value)> FMT_CONSTEXPR20 FMT_INLINE value(T&& val) { *this = arg_mapper::map(val); } - template ::map( - std::declval()))>::value)> + template < + typename T, + typename M = decltype(arg_mapper::map(std::declval())), + FMT_ENABLE_IF(std::is_same::value && + !std::is_integral>::value)> FMT_CONSTEXPR20 FMT_INLINE value(T&& val) { // Use enum instead of constexpr because the latter may generate code. enum { formattable_char = !std::is_same::value }; diff --git a/test/xchar-test.cc b/test/xchar-test.cc index 83b451d4..52946cae 100644 --- a/test/xchar-test.cc +++ b/test/xchar-test.cc @@ -95,93 +95,6 @@ TEST(xchar_test, compile_time_string) { #endif } -#if FMT_CPLUSPLUS > 201103L -struct custom_char { - int value; - custom_char() = default; - - template - constexpr custom_char(T val) : value(static_cast(val)) {} - - constexpr operator char() const { - return value <= 0xff ? static_cast(value) : '\0'; - } - constexpr bool operator<(custom_char c) const { return value < c.value; } -}; - -namespace std { - -template <> struct char_traits { - using char_type = custom_char; - using int_type = int; - using off_type = streamoff; - using pos_type = streampos; - using state_type = mbstate_t; - - static constexpr void assign(char_type& r, const char_type& a) { r = a; } - static constexpr bool eq(char_type a, char_type b) { return a == b; } - static constexpr bool lt(char_type a, char_type b) { return a < b; } - static FMT_CONSTEXPR int compare(const char_type* s1, const char_type* s2, - size_t count) { - for (; count; count--, s1++, s2++) { - if (lt(*s1, *s2)) return -1; - if (lt(*s2, *s1)) return 1; - } - return 0; - } - static FMT_CONSTEXPR size_t length(const char_type* s) { - size_t count = 0; - while (!eq(*s++, custom_char(0))) count++; - return count; - } - static const char_type* find(const char_type*, size_t, const char_type&); - static FMT_CONSTEXPR char_type* move(char_type* dest, const char_type* src, - size_t count) { - if (count == 0) return dest; - char_type* ret = dest; - if (src < dest) { - dest += count; - src += count; - for (; count; count--) assign(*--dest, *--src); - } else if (src > dest) - copy(dest, src, count); - return ret; - } - static FMT_CONSTEXPR char_type* copy(char_type* dest, const char_type* src, - size_t count) { - char_type* ret = dest; - for (; count; count--) assign(*dest++, *src++); - return ret; - } - static FMT_CONSTEXPR char_type* assign(char_type* dest, std::size_t count, - char_type a) { - char_type* ret = dest; - for (; count; count--) assign(*dest++, a); - return ret; - } - static int_type not_eof(int_type); - static char_type to_char_type(int_type); - static int_type to_int_type(char_type); - static bool eq_int_type(int_type, int_type); - static int_type eof(); -}; - -} // namespace std - -auto to_ascii(custom_char c) -> char { return c; } - -FMT_BEGIN_NAMESPACE -template <> struct is_char : std::true_type {}; -FMT_END_NAMESPACE - -TEST(xchar_test, format_custom_char) { - const custom_char format[] = {'{', '}', 0}; - auto result = fmt::format(format, custom_char('x')); - EXPECT_EQ(result.size(), 1); - EXPECT_EQ(result[0], custom_char('x')); -} -#endif - TEST(xchar_test, format_to) { auto buf = std::vector(); fmt::format_to(std::back_inserter(buf), L"{}{}", 42, L'\0');