Skip to content

Commit 34fcab5

Browse files
committed
Merge branch 'master' of https://github.com/Cazadorro/fmt into cuda_agnostic_fractional_part_rounding_thresholds
2 parents 9661f89 + 7b2c4d0 commit 34fcab5

File tree

8 files changed

+108
-81
lines changed

8 files changed

+108
-81
lines changed

.github/workflows/linux.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ jobs:
4848
- cxx: clang++-14
4949
build_type: Debug
5050
std: 20
51+
cxxflags: -fsanitize=address
52+
cxxflags_extra: -fno-sanitize-recover=all -fno-omit-frame-pointer
5153
- cxx: clang++-14
5254
build_type: Debug
5355
std: 20
@@ -154,7 +156,7 @@ jobs:
154156
working-directory: ${{runner.workspace}}/build
155157
env:
156158
CXX: ${{matrix.cxx}}
157-
CXXFLAGS: ${{matrix.cxxflags}}
159+
CXXFLAGS: ${{matrix.cxxflags}} ${{matrix.cxxflags_extra}}
158160
run: |
159161
cmake -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
160162
-DCMAKE_CXX_STANDARD=${{matrix.std}} \

include/fmt/base.h

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1858,6 +1858,65 @@ class fixed_buffer_traits {
18581858
}
18591859
};
18601860

1861+
template <typename OutputIt, typename InputIt, typename = void>
1862+
struct has_back_insert_iterator_container_append : std::false_type {};
1863+
1864+
template <typename OutputIt, typename InputIt>
1865+
struct has_back_insert_iterator_container_append<
1866+
OutputIt, InputIt,
1867+
void_t<decltype(get_container(std::declval<OutputIt>())
1868+
.append(std::declval<InputIt>(),
1869+
std::declval<InputIt>()))>> : std::true_type {};
1870+
1871+
template <typename OutputIt, typename InputIt, typename = void>
1872+
struct has_back_insert_iterator_container_insert_at_end : std::false_type {};
1873+
1874+
template <typename OutputIt, typename InputIt>
1875+
struct has_back_insert_iterator_container_insert_at_end<
1876+
OutputIt, InputIt,
1877+
void_t<decltype(get_container(std::declval<OutputIt>())
1878+
.insert(get_container(std::declval<OutputIt>()).end(),
1879+
std::declval<InputIt>(),
1880+
std::declval<InputIt>()))>> : std::true_type {};
1881+
1882+
// An optimized version of std::copy with the output value type (T).
1883+
template <typename T, typename InputIt, typename OutputIt,
1884+
FMT_ENABLE_IF(is_back_insert_iterator<OutputIt>::value&&
1885+
has_back_insert_iterator_container_append<
1886+
OutputIt, InputIt>::value)>
1887+
FMT_CONSTEXPR auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt {
1888+
get_container(out).append(begin, end);
1889+
return out;
1890+
}
1891+
1892+
template <typename T, typename InputIt, typename OutputIt,
1893+
FMT_ENABLE_IF(is_back_insert_iterator<OutputIt>::value &&
1894+
!has_back_insert_iterator_container_append<
1895+
OutputIt, InputIt>::value &&
1896+
has_back_insert_iterator_container_insert_at_end<
1897+
OutputIt, InputIt>::value)>
1898+
FMT_CONSTEXPR auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt {
1899+
auto& c = get_container(out);
1900+
c.insert(c.end(), begin, end);
1901+
return out;
1902+
}
1903+
1904+
template <typename T, typename InputIt, typename OutputIt,
1905+
FMT_ENABLE_IF(!(is_back_insert_iterator<OutputIt>::value &&
1906+
(has_back_insert_iterator_container_append<
1907+
OutputIt, InputIt>::value ||
1908+
has_back_insert_iterator_container_insert_at_end<
1909+
OutputIt, InputIt>::value)))>
1910+
FMT_CONSTEXPR auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt {
1911+
while (begin != end) *out++ = static_cast<T>(*begin++);
1912+
return out;
1913+
}
1914+
1915+
template <typename T, typename V, typename OutputIt>
1916+
FMT_CONSTEXPR auto copy(basic_string_view<V> s, OutputIt out) -> OutputIt {
1917+
return copy<T>(s.begin(), s.end(), out);
1918+
}
1919+
18611920
// A buffer that writes to an output iterator when flushed.
18621921
template <typename OutputIt, typename T, typename Traits = buffer_traits>
18631922
class iterator_buffer : public Traits, public buffer<T> {
@@ -1875,7 +1934,12 @@ class iterator_buffer : public Traits, public buffer<T> {
18751934
this->clear();
18761935
const T* begin = data_;
18771936
const T* end = begin + this->limit(size);
1878-
while (begin != end) *out_++ = *begin++;
1937+
#if defined(__cpp_if_constexpr)
1938+
if constexpr (std::is_move_assignable<OutputIt>::value)
1939+
out_ = copy<T>(begin, end, out_);
1940+
else
1941+
#endif
1942+
while (begin != end) *out_++ = *begin++;
18791943
}
18801944

18811945
public:

include/fmt/format.h

Lines changed: 0 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -548,65 +548,6 @@ FMT_CONSTEXPR20 auto fill_n(T* out, Size count, char value) -> T* {
548548
return out + count;
549549
}
550550

551-
template <typename OutputIt, typename InputIt, typename = void>
552-
struct has_back_insert_iterator_container_append : std::false_type {};
553-
554-
template <typename OutputIt, typename InputIt>
555-
struct has_back_insert_iterator_container_append<
556-
OutputIt, InputIt,
557-
void_t<decltype(get_container(std::declval<OutputIt>())
558-
.append(std::declval<InputIt>(),
559-
std::declval<InputIt>()))>> : std::true_type {};
560-
561-
template <typename OutputIt, typename InputIt, typename = void>
562-
struct has_back_insert_iterator_container_insert_at_end : std::false_type {};
563-
564-
template <typename OutputIt, typename InputIt>
565-
struct has_back_insert_iterator_container_insert_at_end<
566-
OutputIt, InputIt,
567-
void_t<decltype(get_container(std::declval<OutputIt>())
568-
.insert(get_container(std::declval<OutputIt>()).end(),
569-
std::declval<InputIt>(),
570-
std::declval<InputIt>()))>> : std::true_type {};
571-
572-
// An optimized version of std::copy with the output value type (T).
573-
template <typename T, typename InputIt, typename OutputIt,
574-
FMT_ENABLE_IF(is_back_insert_iterator<OutputIt>::value&&
575-
has_back_insert_iterator_container_append<
576-
OutputIt, InputIt>::value)>
577-
FMT_CONSTEXPR auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt {
578-
get_container(out).append(begin, end);
579-
return out;
580-
}
581-
582-
template <typename T, typename InputIt, typename OutputIt,
583-
FMT_ENABLE_IF(is_back_insert_iterator<OutputIt>::value &&
584-
!has_back_insert_iterator_container_append<
585-
OutputIt, InputIt>::value &&
586-
has_back_insert_iterator_container_insert_at_end<
587-
OutputIt, InputIt>::value)>
588-
FMT_CONSTEXPR auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt {
589-
auto& c = get_container(out);
590-
c.insert(c.end(), begin, end);
591-
return out;
592-
}
593-
594-
template <typename T, typename InputIt, typename OutputIt,
595-
FMT_ENABLE_IF(!(is_back_insert_iterator<OutputIt>::value &&
596-
(has_back_insert_iterator_container_append<
597-
OutputIt, InputIt>::value ||
598-
has_back_insert_iterator_container_insert_at_end<
599-
OutputIt, InputIt>::value)))>
600-
FMT_CONSTEXPR auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt {
601-
while (begin != end) *out++ = static_cast<T>(*begin++);
602-
return out;
603-
}
604-
605-
template <typename T, typename V, typename OutputIt>
606-
FMT_CONSTEXPR auto copy(basic_string_view<V> s, OutputIt out) -> OutputIt {
607-
return copy<T>(s.begin(), s.end(), out);
608-
}
609-
610551
template <typename OutChar, typename InputIt, typename OutputIt>
611552
FMT_CONSTEXPR FMT_NOINLINE auto copy_noinline(InputIt begin, InputIt end,
612553
OutputIt out) -> OutputIt {

include/fmt/printf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@ template <typename Char, typename GetArg>
330330
auto parse_header(const Char*& it, const Char* end, format_specs& specs,
331331
GetArg get_arg) -> int {
332332
int arg_index = -1;
333+
if (it == end) return arg_index;
333334
Char c = *it;
334335
if (c >= '0' && c <= '9') {
335336
// Parse an argument index (if followed by '$') or a width possibly

include/fmt/xchar.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,10 +279,18 @@ inline auto vformat_to_n(OutputIt out, size_t n, basic_string_view<Char> fmt,
279279
return {buf.out(), buf.count()};
280280
}
281281

282+
template <typename OutputIt, typename... T,
283+
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, wchar_t>::value)>
284+
FMT_INLINE auto format_to_n(OutputIt out, size_t n, wformat_string<T...> fmt,
285+
T&&... args) -> format_to_n_result<OutputIt> {
286+
return vformat_to_n(out, n, fmt.get(), fmt::make_wformat_args(args...));
287+
}
288+
282289
template <typename OutputIt, typename S, typename... T,
283290
typename Char = detail::format_string_char_t<S>,
284-
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
285-
detail::is_exotic_char<Char>::value)>
291+
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value &&
292+
!std::is_same<Char, char>::value &&
293+
!std::is_same<Char, wchar_t>::value)>
286294
inline auto format_to_n(OutputIt out, size_t n, const S& fmt, T&&... args)
287295
-> format_to_n_result<OutputIt> {
288296
return vformat_to_n(out, n, fmt::basic_string_view<Char>(fmt),

test/format-test.cc

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -268,22 +268,6 @@ TEST(util_test, format_system_error) {
268268
fmt::format_system_error(message, EDOM, "test");
269269
auto ec = std::error_code(EDOM, std::generic_category());
270270
EXPECT_EQ(to_string(message), std::system_error(ec, "test").what());
271-
message = fmt::memory_buffer();
272-
273-
// Check if std::allocator throws on allocating max size_t / 2 chars.
274-
size_t max_size = max_value<size_t>() / 2;
275-
bool throws_on_alloc = false;
276-
try {
277-
auto alloc = std::allocator<char>();
278-
alloc.deallocate(alloc.allocate(max_size), max_size);
279-
} catch (const std::bad_alloc&) {
280-
throws_on_alloc = true;
281-
}
282-
if (!throws_on_alloc) {
283-
fmt::print(stderr, "warning: std::allocator allocates {} chars\n",
284-
max_size);
285-
return;
286-
}
287271
}
288272

289273
TEST(util_test, system_error) {

test/printf-test.cc

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,8 @@ TEST(printf_test, positional_precision) {
313313
EXPECT_EQ("Hell", test_sprintf("%2$.*1$s", 4, "Hello"));
314314
EXPECT_THROW_MSG(test_sprintf("%2$.*1$d", 5.0, 42), format_error,
315315
"precision is not integer");
316-
EXPECT_THROW_MSG(test_sprintf("%2$.*1$d"), format_error, "argument not found");
316+
EXPECT_THROW_MSG(test_sprintf("%2$.*1$d"), format_error,
317+
"argument not found");
317318
EXPECT_THROW_MSG(test_sprintf("%2$.*1$d", big_num, 42), format_error,
318319
"number is too big");
319320
}
@@ -322,7 +323,8 @@ TEST(printf_test, positional_width_and_precision) {
322323
EXPECT_EQ(" 00042", test_sprintf("%3$*1$.*2$d", 7, 5, 42));
323324
EXPECT_EQ(" ab", test_sprintf("%3$*1$.*2$s", 7, 2, "abcdef"));
324325
EXPECT_EQ(" 00042", test_sprintf("%3$*1$.*2$x", 7, 5, 0x42));
325-
EXPECT_EQ("100.4400000", test_sprintf("%6$-*5$.*4$f%3$s%2$s%1$s", "", "", "", 7, 4, 100.44));
326+
EXPECT_EQ("100.4400000",
327+
test_sprintf("%6$-*5$.*4$f%3$s%2$s%1$s", "", "", "", 7, 4, 100.44));
326328
}
327329

328330
template <typename T> struct make_signed {
@@ -555,3 +557,8 @@ TEST(printf_test, make_printf_args) {
555557
fmt::vsprintf(fmt::basic_string_view<wchar_t>(L"[%d] %s happened"),
556558
{fmt::make_printf_args<wchar_t>(n, L"something")}));
557559
}
560+
561+
TEST(printf_test, trailing_percent_non_nul_terminated) {
562+
auto p = std::unique_ptr<char>(new char('%'));
563+
EXPECT_THROW(fmt::sprintf(fmt::string_view(p.get(), 1)), format_error);
564+
}

test/xchar-test.cc

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,26 @@ TEST(format_test, wide_format_to_n) {
146146
EXPECT_EQ(L"BC x", fmt::wstring_view(buffer, 4));
147147
}
148148

149+
TEST(format_test, wide_format_to_n_runtime) {
150+
wchar_t buffer[4];
151+
buffer[3] = L'x';
152+
auto result = fmt::format_to_n(buffer, 3, fmt::runtime(L"{}"), 12345);
153+
EXPECT_EQ(5u, result.size);
154+
EXPECT_EQ(buffer + 3, result.out);
155+
EXPECT_EQ(L"123x", fmt::wstring_view(buffer, 4));
156+
buffer[0] = L'x';
157+
buffer[1] = L'x';
158+
buffer[2] = L'x';
159+
result = fmt::format_to_n(buffer, 3, fmt::runtime(L"{}"), L'A');
160+
EXPECT_EQ(1u, result.size);
161+
EXPECT_EQ(buffer + 1, result.out);
162+
EXPECT_EQ(L"Axxx", fmt::wstring_view(buffer, 4));
163+
result = fmt::format_to_n(buffer, 3, fmt::runtime(L"{}{} "), L'B', L'C');
164+
EXPECT_EQ(3u, result.size);
165+
EXPECT_EQ(buffer + 3, result.out);
166+
EXPECT_EQ(L"BC x", fmt::wstring_view(buffer, 4));
167+
}
168+
149169
TEST(xchar_test, named_arg_udl) {
150170
using namespace fmt::literals;
151171
auto udl_a =

0 commit comments

Comments
 (0)