Move detail::truncating_iterator to fmt/compile.h
This commit is contained in:
parent
e718ec3e93
commit
6e1fc01752
@ -25,6 +25,85 @@
|
|||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
template <typename OutputIt> class truncating_iterator_base {
|
||||||
|
protected:
|
||||||
|
OutputIt out_;
|
||||||
|
size_t limit_;
|
||||||
|
size_t count_ = 0;
|
||||||
|
|
||||||
|
truncating_iterator_base() : out_(), limit_(0) {}
|
||||||
|
|
||||||
|
truncating_iterator_base(OutputIt out, size_t limit)
|
||||||
|
: out_(out), limit_(limit) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
using iterator_category = std::output_iterator_tag;
|
||||||
|
using value_type = typename std::iterator_traits<OutputIt>::value_type;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using pointer = void;
|
||||||
|
using reference = void;
|
||||||
|
using _Unchecked_type =
|
||||||
|
truncating_iterator_base; // Mark iterator as checked.
|
||||||
|
|
||||||
|
OutputIt base() const { return out_; }
|
||||||
|
size_t count() const { return count_; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// An output iterator that truncates the output and counts the number of objects
|
||||||
|
// written to it.
|
||||||
|
template <typename OutputIt,
|
||||||
|
typename Enable = typename std::is_void<
|
||||||
|
typename std::iterator_traits<OutputIt>::value_type>::type>
|
||||||
|
class truncating_iterator;
|
||||||
|
|
||||||
|
template <typename OutputIt>
|
||||||
|
class truncating_iterator<OutputIt, std::false_type>
|
||||||
|
: public truncating_iterator_base<OutputIt> {
|
||||||
|
mutable typename truncating_iterator_base<OutputIt>::value_type blackhole_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type = typename truncating_iterator_base<OutputIt>::value_type;
|
||||||
|
|
||||||
|
truncating_iterator() = default;
|
||||||
|
|
||||||
|
truncating_iterator(OutputIt out, size_t limit)
|
||||||
|
: truncating_iterator_base<OutputIt>(out, limit) {}
|
||||||
|
|
||||||
|
truncating_iterator& operator++() {
|
||||||
|
if (this->count_++ < this->limit_) ++this->out_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
truncating_iterator operator++(int) {
|
||||||
|
auto it = *this;
|
||||||
|
++*this;
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
value_type& operator*() const {
|
||||||
|
return this->count_ < this->limit_ ? *this->out_ : blackhole_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename OutputIt>
|
||||||
|
class truncating_iterator<OutputIt, std::true_type>
|
||||||
|
: public truncating_iterator_base<OutputIt> {
|
||||||
|
public:
|
||||||
|
truncating_iterator() = default;
|
||||||
|
|
||||||
|
truncating_iterator(OutputIt out, size_t limit)
|
||||||
|
: truncating_iterator_base<OutputIt>(out, limit) {}
|
||||||
|
|
||||||
|
template <typename T> truncating_iterator& operator=(T val) {
|
||||||
|
if (this->count_++ < this->limit_) *this->out_++ = val;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
truncating_iterator& operator++() { return *this; }
|
||||||
|
truncating_iterator& operator++(int) { return *this; }
|
||||||
|
truncating_iterator& operator*() { return *this; }
|
||||||
|
};
|
||||||
|
|
||||||
// A compile-time string which is compiled into fast formatting code.
|
// A compile-time string which is compiled into fast formatting code.
|
||||||
class compiled_string {};
|
class compiled_string {};
|
||||||
|
|
||||||
|
@ -465,85 +465,6 @@ class counting_iterator {
|
|||||||
value_type operator*() const { return {}; }
|
value_type operator*() const { return {}; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename OutputIt> class truncating_iterator_base {
|
|
||||||
protected:
|
|
||||||
OutputIt out_;
|
|
||||||
size_t limit_;
|
|
||||||
size_t count_ = 0;
|
|
||||||
|
|
||||||
truncating_iterator_base() : out_(), limit_(0) {}
|
|
||||||
|
|
||||||
truncating_iterator_base(OutputIt out, size_t limit)
|
|
||||||
: out_(out), limit_(limit) {}
|
|
||||||
|
|
||||||
public:
|
|
||||||
using iterator_category = std::output_iterator_tag;
|
|
||||||
using value_type = typename std::iterator_traits<OutputIt>::value_type;
|
|
||||||
using difference_type = std::ptrdiff_t;
|
|
||||||
using pointer = void;
|
|
||||||
using reference = void;
|
|
||||||
using _Unchecked_type =
|
|
||||||
truncating_iterator_base; // Mark iterator as checked.
|
|
||||||
|
|
||||||
OutputIt base() const { return out_; }
|
|
||||||
size_t count() const { return count_; }
|
|
||||||
};
|
|
||||||
|
|
||||||
// An output iterator that truncates the output and counts the number of objects
|
|
||||||
// written to it.
|
|
||||||
template <typename OutputIt,
|
|
||||||
typename Enable = typename std::is_void<
|
|
||||||
typename std::iterator_traits<OutputIt>::value_type>::type>
|
|
||||||
class truncating_iterator;
|
|
||||||
|
|
||||||
template <typename OutputIt>
|
|
||||||
class truncating_iterator<OutputIt, std::false_type>
|
|
||||||
: public truncating_iterator_base<OutputIt> {
|
|
||||||
mutable typename truncating_iterator_base<OutputIt>::value_type blackhole_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using value_type = typename truncating_iterator_base<OutputIt>::value_type;
|
|
||||||
|
|
||||||
truncating_iterator() = default;
|
|
||||||
|
|
||||||
truncating_iterator(OutputIt out, size_t limit)
|
|
||||||
: truncating_iterator_base<OutputIt>(out, limit) {}
|
|
||||||
|
|
||||||
truncating_iterator& operator++() {
|
|
||||||
if (this->count_++ < this->limit_) ++this->out_;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
truncating_iterator operator++(int) {
|
|
||||||
auto it = *this;
|
|
||||||
++*this;
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type& operator*() const {
|
|
||||||
return this->count_ < this->limit_ ? *this->out_ : blackhole_;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename OutputIt>
|
|
||||||
class truncating_iterator<OutputIt, std::true_type>
|
|
||||||
: public truncating_iterator_base<OutputIt> {
|
|
||||||
public:
|
|
||||||
truncating_iterator() = default;
|
|
||||||
|
|
||||||
truncating_iterator(OutputIt out, size_t limit)
|
|
||||||
: truncating_iterator_base<OutputIt>(out, limit) {}
|
|
||||||
|
|
||||||
template <typename T> truncating_iterator& operator=(T val) {
|
|
||||||
if (this->count_++ < this->limit_) *this->out_++ = val;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
truncating_iterator& operator++() { return *this; }
|
|
||||||
truncating_iterator& operator++(int) { return *this; }
|
|
||||||
truncating_iterator& operator*() { return *this; }
|
|
||||||
};
|
|
||||||
|
|
||||||
// <algorithm> is spectacularly slow to compile in C++20 so use a simple fill_n
|
// <algorithm> is spectacularly slow to compile in C++20 so use a simple fill_n
|
||||||
// instead (#1998).
|
// instead (#1998).
|
||||||
template <typename OutputIt, typename Size, typename T>
|
template <typename OutputIt, typename Size, typename T>
|
||||||
|
@ -19,6 +19,43 @@
|
|||||||
#include "gtest-extra.h"
|
#include "gtest-extra.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
TEST(IteratorTest, TruncatingIterator) {
|
||||||
|
char* p = nullptr;
|
||||||
|
fmt::detail::truncating_iterator<char*> it(p, 3);
|
||||||
|
auto prev = it++;
|
||||||
|
EXPECT_EQ(prev.base(), p);
|
||||||
|
EXPECT_EQ(it.base(), p + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(IteratorTest, TruncatingIteratorDefaultConstruct) {
|
||||||
|
static_assert(
|
||||||
|
std::is_default_constructible<fmt::detail::truncating_iterator<char*>>::value,
|
||||||
|
"");
|
||||||
|
|
||||||
|
fmt::detail::truncating_iterator<char*> it;
|
||||||
|
EXPECT_EQ(nullptr, it.base());
|
||||||
|
EXPECT_EQ(std::size_t{0}, it.count());
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cpp_lib_ranges
|
||||||
|
TEST(IteratorTest, TruncatingIteratorOutputIterator) {
|
||||||
|
static_assert(std::output_iterator<fmt::detail::truncating_iterator<char*>,
|
||||||
|
char>);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TEST(IteratorTest, TruncatingBackInserter) {
|
||||||
|
std::string buffer;
|
||||||
|
auto bi = std::back_inserter(buffer);
|
||||||
|
fmt::detail::truncating_iterator<decltype(bi)> it(bi, 2);
|
||||||
|
*it++ = '4';
|
||||||
|
*it++ = '2';
|
||||||
|
*it++ = '1';
|
||||||
|
EXPECT_EQ(buffer.size(), 2);
|
||||||
|
EXPECT_EQ(buffer, "42");
|
||||||
|
}
|
||||||
|
|
||||||
// compiletime_prepared_parts_type_provider is useful only with relaxed
|
// compiletime_prepared_parts_type_provider is useful only with relaxed
|
||||||
// constexpr.
|
// constexpr.
|
||||||
#if FMT_USE_CONSTEXPR
|
#if FMT_USE_CONSTEXPR
|
||||||
|
@ -151,43 +151,6 @@ TEST(IteratorTest, CountingIterator) {
|
|||||||
EXPECT_EQ((it + 41).count(), 42);
|
EXPECT_EQ((it + 41).count(), 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(IteratorTest, TruncatingIterator) {
|
|
||||||
char* p = nullptr;
|
|
||||||
fmt::detail::truncating_iterator<char*> it(p, 3);
|
|
||||||
auto prev = it++;
|
|
||||||
EXPECT_EQ(prev.base(), p);
|
|
||||||
EXPECT_EQ(it.base(), p + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
TEST(IteratorTest, TruncatingIteratorDefaultConstruct) {
|
|
||||||
static_assert(
|
|
||||||
std::is_default_constructible<fmt::detail::truncating_iterator<char*>>::value,
|
|
||||||
"");
|
|
||||||
|
|
||||||
fmt::detail::truncating_iterator<char*> it;
|
|
||||||
EXPECT_EQ(nullptr, it.base());
|
|
||||||
EXPECT_EQ(std::size_t{0}, it.count());
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cpp_lib_ranges
|
|
||||||
TEST(IteratorTest, TruncatingIteratorOutputIterator) {
|
|
||||||
static_assert(std::output_iterator<fmt::detail::truncating_iterator<char*>,
|
|
||||||
char>);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
TEST(IteratorTest, TruncatingBackInserter) {
|
|
||||||
std::string buffer;
|
|
||||||
auto bi = std::back_inserter(buffer);
|
|
||||||
fmt::detail::truncating_iterator<decltype(bi)> it(bi, 2);
|
|
||||||
*it++ = '4';
|
|
||||||
*it++ = '2';
|
|
||||||
*it++ = '1';
|
|
||||||
EXPECT_EQ(buffer.size(), 2);
|
|
||||||
EXPECT_EQ(buffer, "42");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(IteratorTest, IsOutputIterator) {
|
TEST(IteratorTest, IsOutputIterator) {
|
||||||
EXPECT_TRUE((fmt::detail::is_output_iterator<char*, char>::value));
|
EXPECT_TRUE((fmt::detail::is_output_iterator<char*, char>::value));
|
||||||
EXPECT_FALSE((fmt::detail::is_output_iterator<const char*, char>::value));
|
EXPECT_FALSE((fmt::detail::is_output_iterator<const char*, char>::value));
|
||||||
|
@ -606,23 +606,3 @@ TEST(PrintfTest, VSPrintfMakeWArgsExample) {
|
|||||||
{fmt::make_wprintf_args(42, L"something")}));
|
{fmt::make_wprintf_args(42, L"something")}));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PrintfTest, PrintfDetermineOutputSize) {
|
|
||||||
using backit = std::back_insert_iterator<std::vector<char>>;
|
|
||||||
using truncated_printf_context =
|
|
||||||
fmt::basic_printf_context<fmt::detail::truncating_iterator<backit>, char>;
|
|
||||||
|
|
||||||
auto v = std::vector<char>{};
|
|
||||||
auto it = std::back_inserter(v);
|
|
||||||
|
|
||||||
const auto format_string = "%s";
|
|
||||||
const auto format_arg = "Hello";
|
|
||||||
const auto expected_size = fmt::sprintf(format_string, format_arg).size();
|
|
||||||
|
|
||||||
EXPECT_EQ((truncated_printf_context(
|
|
||||||
fmt::detail::truncating_iterator<backit>(it, 0), format_string,
|
|
||||||
fmt::make_format_args<truncated_printf_context>(format_arg))
|
|
||||||
.format()
|
|
||||||
.count()),
|
|
||||||
expected_size);
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user