Update fmt::join to support more character types (#4686)
This commit is contained in:
@@ -1809,6 +1809,8 @@ template <typename T> class buffer {
|
||||
/// Appends data to the end of the buffer.
|
||||
template <typename U>
|
||||
FMT_CONSTEXPR20 void append(const U* begin, const U* end) {
|
||||
static_assert(std::is_same<T, U>::value || std::is_same<U, char>::value,
|
||||
"U must be T or char to prevent static_cast overflow");
|
||||
while (begin != end) {
|
||||
auto size = size_;
|
||||
auto free_cap = capacity_ - size;
|
||||
@@ -1821,7 +1823,7 @@ template <typename T> class buffer {
|
||||
}
|
||||
// A loop is faster than memcpy on small sizes.
|
||||
T* out = ptr_ + size;
|
||||
for (size_t i = 0; i < count; ++i) out[i] = begin[i];
|
||||
for (size_t i = 0; i < count; ++i) out[i] = static_cast<T>(begin[i]);
|
||||
size_ += count;
|
||||
begin += count;
|
||||
}
|
||||
|
||||
@@ -1097,8 +1097,8 @@ inline auto digits2_i(size_t value) noexcept -> const char* {
|
||||
}
|
||||
|
||||
template <typename Char> constexpr auto getsign(sign s) -> Char {
|
||||
return static_cast<char>(((' ' << 24) | ('+' << 16) | ('-' << 8)) >>
|
||||
(static_cast<int>(s) * 8));
|
||||
return static_cast<Char>(static_cast<char>(
|
||||
((' ' << 24) | ('+' << 16) | ('-' << 8)) >> (static_cast<int>(s) * 8)));
|
||||
}
|
||||
|
||||
template <typename T> FMT_CONSTEXPR auto count_digits_fallback(T n) -> int {
|
||||
@@ -3621,8 +3621,8 @@ FMT_CONSTEXPR20 auto write(OutputIt out, T value) -> OutputIt {
|
||||
memcpy(ptr, prefix, 2);
|
||||
ptr += 2;
|
||||
} else {
|
||||
*ptr++ = prefix[0];
|
||||
*ptr++ = prefix[1];
|
||||
*ptr++ = static_cast<Char>(prefix[0]);
|
||||
*ptr++ = static_cast<Char>(prefix[1]);
|
||||
}
|
||||
if (abs_exponent >= 100) {
|
||||
*ptr++ = static_cast<Char>('0' + abs_exponent / 100);
|
||||
|
||||
@@ -141,17 +141,22 @@ auto arg(const wchar_t* name, const T& arg) -> named_arg<T, wchar_t> {
|
||||
return {name, arg};
|
||||
}
|
||||
|
||||
template <typename It, typename Sentinel>
|
||||
auto join(It begin, Sentinel end, wstring_view sep)
|
||||
-> join_view<It, Sentinel, wchar_t> {
|
||||
return {begin, end, sep};
|
||||
template <typename It, typename Sentinel, typename S,
|
||||
typename Char = typename decltype(detail::to_string_view(
|
||||
std::declval<S>()))::value_type,
|
||||
FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)>
|
||||
auto join(It begin, Sentinel end, S&& sep) -> join_view<It, Sentinel, Char> {
|
||||
return {begin, end, detail::to_string_view(sep)};
|
||||
}
|
||||
|
||||
template <typename Range, FMT_ENABLE_IF(!is_tuple_like<Range>::value)>
|
||||
auto join(Range&& range, wstring_view sep)
|
||||
-> join_view<decltype(std::begin(range)), decltype(std::end(range)),
|
||||
wchar_t> {
|
||||
return join(std::begin(range), std::end(range), sep);
|
||||
template <typename Range, typename S,
|
||||
typename Char = typename decltype(detail::to_string_view(
|
||||
std::declval<S>()))::value_type,
|
||||
FMT_ENABLE_IF(detail::is_exotic_char<Char>::value &&
|
||||
!is_tuple_like<Range>::value)>
|
||||
auto join(Range&& range, S&& sep)
|
||||
-> join_view<decltype(std::begin(range)), decltype(std::end(range)), Char> {
|
||||
return {std::begin(range), std::end(range), detail::to_string_view(sep)};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -160,10 +165,13 @@ auto join(std::initializer_list<T> list, wstring_view sep)
|
||||
return join(std::begin(list), std::end(list), sep);
|
||||
}
|
||||
|
||||
template <typename Tuple, FMT_ENABLE_IF(is_tuple_like<Tuple>::value)>
|
||||
auto join(const Tuple& tuple, basic_string_view<wchar_t> sep)
|
||||
-> tuple_join_view<Tuple, wchar_t> {
|
||||
return {tuple, sep};
|
||||
template <typename Tuple, typename S,
|
||||
typename Char = typename decltype(detail::to_string_view(
|
||||
std::declval<S>()))::value_type,
|
||||
FMT_ENABLE_IF(detail::is_exotic_char<Char>::value&&
|
||||
is_tuple_like<Tuple>::value)>
|
||||
auto join(const Tuple& tuple, S&& sep) -> tuple_join_view<Tuple, Char> {
|
||||
return {tuple, detail::to_string_view(sep)};
|
||||
}
|
||||
|
||||
template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
|
||||
|
||||
@@ -167,9 +167,20 @@ TEST(xchar_test, print) {
|
||||
|
||||
TEST(xchar_test, join) {
|
||||
int v[3] = {1, 2, 3};
|
||||
EXPECT_EQ(fmt::format(u"({})", fmt::join(v, v + 3, u", ")), u"(1, 2, 3)");
|
||||
EXPECT_EQ(fmt::format(U"({})", fmt::join(v, v + 3, U", ")), U"(1, 2, 3)");
|
||||
EXPECT_EQ(fmt::format(L"({})", fmt::join(v, v + 3, L", ")), L"(1, 2, 3)");
|
||||
auto t = std::tuple<wchar_t, int, float>('a', 1, 2.0f);
|
||||
EXPECT_EQ(fmt::format(L"({})", fmt::join(t, L", ")), L"(a, 1, 2)");
|
||||
auto vector = std::vector<int>{1, 2, 3};
|
||||
EXPECT_EQ(fmt::format(u"({})", fmt::join(vector, u", ")), u"(1, 2, 3)");
|
||||
EXPECT_EQ(fmt::format(U"({})", fmt::join(vector, U", ")), U"(1, 2, 3)");
|
||||
EXPECT_EQ(fmt::format(L"({})", fmt::join(vector, L", ")), L"(1, 2, 3)");
|
||||
EXPECT_EQ(fmt::format(L"({})", fmt::join({1, 2, 3}, L", ")), L"(1, 2, 3)");
|
||||
auto tuple_char16 = std::tuple<char16_t, int, float>(u'a', 1, 2.0f);
|
||||
EXPECT_EQ(fmt::format(u"({})", fmt::join(tuple_char16, u", ")), u"(a, 1, 2)");
|
||||
auto tuple_char32 = std::tuple<char32_t, int, float>(U'a', 1, 2.0f);
|
||||
EXPECT_EQ(fmt::format(U"({})", fmt::join(tuple_char32, U", ")), U"(a, 1, 2)");
|
||||
auto tuple_wchar = std::tuple<wchar_t, int, float>(L'a', 1, 2.0f);
|
||||
EXPECT_EQ(fmt::format(L"({})", fmt::join(tuple_wchar, L", ")), L"(a, 1, 2)");
|
||||
}
|
||||
|
||||
#ifdef __cpp_lib_byte
|
||||
|
||||
Reference in New Issue
Block a user