Skip to content

Commit 6e1fc01

Browse files
committed
Move detail::truncating_iterator to fmt/compile.h
1 parent e718ec3 commit 6e1fc01

File tree

5 files changed

+116
-136
lines changed

5 files changed

+116
-136
lines changed

include/fmt/compile.h

+79
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,85 @@
2525
FMT_BEGIN_NAMESPACE
2626
namespace detail {
2727

28+
template <typename OutputIt> class truncating_iterator_base {
29+
protected:
30+
OutputIt out_;
31+
size_t limit_;
32+
size_t count_ = 0;
33+
34+
truncating_iterator_base() : out_(), limit_(0) {}
35+
36+
truncating_iterator_base(OutputIt out, size_t limit)
37+
: out_(out), limit_(limit) {}
38+
39+
public:
40+
using iterator_category = std::output_iterator_tag;
41+
using value_type = typename std::iterator_traits<OutputIt>::value_type;
42+
using difference_type = std::ptrdiff_t;
43+
using pointer = void;
44+
using reference = void;
45+
using _Unchecked_type =
46+
truncating_iterator_base; // Mark iterator as checked.
47+
48+
OutputIt base() const { return out_; }
49+
size_t count() const { return count_; }
50+
};
51+
52+
// An output iterator that truncates the output and counts the number of objects
53+
// written to it.
54+
template <typename OutputIt,
55+
typename Enable = typename std::is_void<
56+
typename std::iterator_traits<OutputIt>::value_type>::type>
57+
class truncating_iterator;
58+
59+
template <typename OutputIt>
60+
class truncating_iterator<OutputIt, std::false_type>
61+
: public truncating_iterator_base<OutputIt> {
62+
mutable typename truncating_iterator_base<OutputIt>::value_type blackhole_;
63+
64+
public:
65+
using value_type = typename truncating_iterator_base<OutputIt>::value_type;
66+
67+
truncating_iterator() = default;
68+
69+
truncating_iterator(OutputIt out, size_t limit)
70+
: truncating_iterator_base<OutputIt>(out, limit) {}
71+
72+
truncating_iterator& operator++() {
73+
if (this->count_++ < this->limit_) ++this->out_;
74+
return *this;
75+
}
76+
77+
truncating_iterator operator++(int) {
78+
auto it = *this;
79+
++*this;
80+
return it;
81+
}
82+
83+
value_type& operator*() const {
84+
return this->count_ < this->limit_ ? *this->out_ : blackhole_;
85+
}
86+
};
87+
88+
template <typename OutputIt>
89+
class truncating_iterator<OutputIt, std::true_type>
90+
: public truncating_iterator_base<OutputIt> {
91+
public:
92+
truncating_iterator() = default;
93+
94+
truncating_iterator(OutputIt out, size_t limit)
95+
: truncating_iterator_base<OutputIt>(out, limit) {}
96+
97+
template <typename T> truncating_iterator& operator=(T val) {
98+
if (this->count_++ < this->limit_) *this->out_++ = val;
99+
return *this;
100+
}
101+
102+
truncating_iterator& operator++() { return *this; }
103+
truncating_iterator& operator++(int) { return *this; }
104+
truncating_iterator& operator*() { return *this; }
105+
};
106+
28107
// A compile-time string which is compiled into fast formatting code.
29108
class compiled_string {};
30109

include/fmt/format.h

-79
Original file line numberDiff line numberDiff line change
@@ -465,85 +465,6 @@ class counting_iterator {
465465
value_type operator*() const { return {}; }
466466
};
467467

468-
template <typename OutputIt> class truncating_iterator_base {
469-
protected:
470-
OutputIt out_;
471-
size_t limit_;
472-
size_t count_ = 0;
473-
474-
truncating_iterator_base() : out_(), limit_(0) {}
475-
476-
truncating_iterator_base(OutputIt out, size_t limit)
477-
: out_(out), limit_(limit) {}
478-
479-
public:
480-
using iterator_category = std::output_iterator_tag;
481-
using value_type = typename std::iterator_traits<OutputIt>::value_type;
482-
using difference_type = std::ptrdiff_t;
483-
using pointer = void;
484-
using reference = void;
485-
using _Unchecked_type =
486-
truncating_iterator_base; // Mark iterator as checked.
487-
488-
OutputIt base() const { return out_; }
489-
size_t count() const { return count_; }
490-
};
491-
492-
// An output iterator that truncates the output and counts the number of objects
493-
// written to it.
494-
template <typename OutputIt,
495-
typename Enable = typename std::is_void<
496-
typename std::iterator_traits<OutputIt>::value_type>::type>
497-
class truncating_iterator;
498-
499-
template <typename OutputIt>
500-
class truncating_iterator<OutputIt, std::false_type>
501-
: public truncating_iterator_base<OutputIt> {
502-
mutable typename truncating_iterator_base<OutputIt>::value_type blackhole_;
503-
504-
public:
505-
using value_type = typename truncating_iterator_base<OutputIt>::value_type;
506-
507-
truncating_iterator() = default;
508-
509-
truncating_iterator(OutputIt out, size_t limit)
510-
: truncating_iterator_base<OutputIt>(out, limit) {}
511-
512-
truncating_iterator& operator++() {
513-
if (this->count_++ < this->limit_) ++this->out_;
514-
return *this;
515-
}
516-
517-
truncating_iterator operator++(int) {
518-
auto it = *this;
519-
++*this;
520-
return it;
521-
}
522-
523-
value_type& operator*() const {
524-
return this->count_ < this->limit_ ? *this->out_ : blackhole_;
525-
}
526-
};
527-
528-
template <typename OutputIt>
529-
class truncating_iterator<OutputIt, std::true_type>
530-
: public truncating_iterator_base<OutputIt> {
531-
public:
532-
truncating_iterator() = default;
533-
534-
truncating_iterator(OutputIt out, size_t limit)
535-
: truncating_iterator_base<OutputIt>(out, limit) {}
536-
537-
template <typename T> truncating_iterator& operator=(T val) {
538-
if (this->count_++ < this->limit_) *this->out_++ = val;
539-
return *this;
540-
}
541-
542-
truncating_iterator& operator++() { return *this; }
543-
truncating_iterator& operator++(int) { return *this; }
544-
truncating_iterator& operator*() { return *this; }
545-
};
546-
547468
// <algorithm> is spectacularly slow to compile in C++20 so use a simple fill_n
548469
// instead (#1998).
549470
template <typename OutputIt, typename Size, typename T>

test/compile-test.cc

+37
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,43 @@
1919
#include "gtest-extra.h"
2020
#include "util.h"
2121

22+
TEST(IteratorTest, TruncatingIterator) {
23+
char* p = nullptr;
24+
fmt::detail::truncating_iterator<char*> it(p, 3);
25+
auto prev = it++;
26+
EXPECT_EQ(prev.base(), p);
27+
EXPECT_EQ(it.base(), p + 1);
28+
}
29+
30+
31+
TEST(IteratorTest, TruncatingIteratorDefaultConstruct) {
32+
static_assert(
33+
std::is_default_constructible<fmt::detail::truncating_iterator<char*>>::value,
34+
"");
35+
36+
fmt::detail::truncating_iterator<char*> it;
37+
EXPECT_EQ(nullptr, it.base());
38+
EXPECT_EQ(std::size_t{0}, it.count());
39+
}
40+
41+
#ifdef __cpp_lib_ranges
42+
TEST(IteratorTest, TruncatingIteratorOutputIterator) {
43+
static_assert(std::output_iterator<fmt::detail::truncating_iterator<char*>,
44+
char>);
45+
}
46+
#endif
47+
48+
TEST(IteratorTest, TruncatingBackInserter) {
49+
std::string buffer;
50+
auto bi = std::back_inserter(buffer);
51+
fmt::detail::truncating_iterator<decltype(bi)> it(bi, 2);
52+
*it++ = '4';
53+
*it++ = '2';
54+
*it++ = '1';
55+
EXPECT_EQ(buffer.size(), 2);
56+
EXPECT_EQ(buffer, "42");
57+
}
58+
2259
// compiletime_prepared_parts_type_provider is useful only with relaxed
2360
// constexpr.
2461
#if FMT_USE_CONSTEXPR

test/format-test.cc

-37
Original file line numberDiff line numberDiff line change
@@ -151,43 +151,6 @@ TEST(IteratorTest, CountingIterator) {
151151
EXPECT_EQ((it + 41).count(), 42);
152152
}
153153

154-
TEST(IteratorTest, TruncatingIterator) {
155-
char* p = nullptr;
156-
fmt::detail::truncating_iterator<char*> it(p, 3);
157-
auto prev = it++;
158-
EXPECT_EQ(prev.base(), p);
159-
EXPECT_EQ(it.base(), p + 1);
160-
}
161-
162-
163-
TEST(IteratorTest, TruncatingIteratorDefaultConstruct) {
164-
static_assert(
165-
std::is_default_constructible<fmt::detail::truncating_iterator<char*>>::value,
166-
"");
167-
168-
fmt::detail::truncating_iterator<char*> it;
169-
EXPECT_EQ(nullptr, it.base());
170-
EXPECT_EQ(std::size_t{0}, it.count());
171-
}
172-
173-
#ifdef __cpp_lib_ranges
174-
TEST(IteratorTest, TruncatingIteratorOutputIterator) {
175-
static_assert(std::output_iterator<fmt::detail::truncating_iterator<char*>,
176-
char>);
177-
}
178-
#endif
179-
180-
TEST(IteratorTest, TruncatingBackInserter) {
181-
std::string buffer;
182-
auto bi = std::back_inserter(buffer);
183-
fmt::detail::truncating_iterator<decltype(bi)> it(bi, 2);
184-
*it++ = '4';
185-
*it++ = '2';
186-
*it++ = '1';
187-
EXPECT_EQ(buffer.size(), 2);
188-
EXPECT_EQ(buffer, "42");
189-
}
190-
191154
TEST(IteratorTest, IsOutputIterator) {
192155
EXPECT_TRUE((fmt::detail::is_output_iterator<char*, char>::value));
193156
EXPECT_FALSE((fmt::detail::is_output_iterator<const char*, char>::value));

test/printf-test.cc

-20
Original file line numberDiff line numberDiff line change
@@ -606,23 +606,3 @@ TEST(PrintfTest, VSPrintfMakeWArgsExample) {
606606
{fmt::make_wprintf_args(42, L"something")}));
607607
#endif
608608
}
609-
610-
TEST(PrintfTest, PrintfDetermineOutputSize) {
611-
using backit = std::back_insert_iterator<std::vector<char>>;
612-
using truncated_printf_context =
613-
fmt::basic_printf_context<fmt::detail::truncating_iterator<backit>, char>;
614-
615-
auto v = std::vector<char>{};
616-
auto it = std::back_inserter(v);
617-
618-
const auto format_string = "%s";
619-
const auto format_arg = "Hello";
620-
const auto expected_size = fmt::sprintf(format_string, format_arg).size();
621-
622-
EXPECT_EQ((truncated_printf_context(
623-
fmt::detail::truncating_iterator<backit>(it, 0), format_string,
624-
fmt::make_format_args<truncated_printf_context>(format_arg))
625-
.format()
626-
.count()),
627-
expected_size);
628-
}

0 commit comments

Comments
 (0)