Update fmt::join to support more character types (#4686)

This commit is contained in:
Yancey
2026-03-05 00:14:08 +08:00
committed by GitHub
parent e2bf61cdf8
commit 8277ee6aa0
4 changed files with 41 additions and 20 deletions

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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)>

View File

@@ -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