mirror of
https://github.com/fmtlib/fmt.git
synced 2024-11-07 08:31:16 +00:00
fix: 'format_to_n' compiles 'std::back_inserter' arguments
std::back_insert_iterators model the OutputIterator concept but differ considerably in their traits and behavior. In particular the former made compilation to fail when format_to_n is given a back_inserter as first argument. The emulation of an OutputIterator is not perfect due to the behavioural differences of back_insert_iterators (e.g. assignment always implies increment) but good enough to be used within fmt's machinery.
This commit is contained in:
parent
f0328f8e36
commit
1e3dcbba81
@ -738,35 +738,49 @@ class counting_iterator {
|
||||
T &operator*() const { return blackhole_; }
|
||||
};
|
||||
|
||||
// An output iterator that truncates the output and counts the number of objects
|
||||
// written to it.
|
||||
template <typename OutputIt>
|
||||
class truncating_iterator {
|
||||
private:
|
||||
typedef std::iterator_traits<OutputIt> traits;
|
||||
|
||||
class truncating_iterator_base {
|
||||
protected:
|
||||
OutputIt out_;
|
||||
std::size_t limit_;
|
||||
std::size_t count_;
|
||||
mutable typename traits::value_type blackhole_;
|
||||
|
||||
truncating_iterator_base(OutputIt out, std::size_t limit)
|
||||
: out_(out), limit_(limit), count_(0) {}
|
||||
|
||||
public:
|
||||
typedef std::output_iterator_tag iterator_category;
|
||||
typedef typename traits::value_type value_type;
|
||||
typedef typename traits::difference_type difference_type;
|
||||
typedef typename traits::pointer pointer;
|
||||
typedef typename traits::reference reference;
|
||||
typedef truncating_iterator _Unchecked_type; // Mark iterator as checked.
|
||||
|
||||
truncating_iterator(OutputIt out, std::size_t limit)
|
||||
: out_(out), limit_(limit), count_(0) {}
|
||||
typedef void difference_type;
|
||||
typedef void pointer;
|
||||
typedef void reference;
|
||||
typedef truncating_iterator_base _Unchecked_type; // Mark iterator as checked.
|
||||
|
||||
OutputIt base() const { return out_; }
|
||||
std::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> {
|
||||
typedef std::iterator_traits<OutputIt> traits;
|
||||
|
||||
mutable typename traits::value_type blackhole_;
|
||||
|
||||
public:
|
||||
typedef typename traits::value_type value_type;
|
||||
|
||||
truncating_iterator(OutputIt out, std::size_t limit)
|
||||
: truncating_iterator_base<OutputIt>(out, limit) {}
|
||||
|
||||
truncating_iterator& operator++() {
|
||||
if (count_++ < limit_)
|
||||
++out_;
|
||||
if (this->count_++ < this->limit_)
|
||||
++this->out_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -776,7 +790,31 @@ class truncating_iterator {
|
||||
return it;
|
||||
}
|
||||
|
||||
reference operator*() const { return count_ < limit_ ? *out_ : blackhole_; }
|
||||
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:
|
||||
typedef typename OutputIt::container_type::value_type value_type;
|
||||
|
||||
truncating_iterator(OutputIt out, std::size_t limit)
|
||||
: truncating_iterator_base<OutputIt>(out, limit) {}
|
||||
|
||||
truncating_iterator& operator=(value_type 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; }
|
||||
};
|
||||
|
||||
// Returns true if value is negative, false otherwise.
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <cstring>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
// Check if fmt/format.h compiles with windows.h included before it.
|
||||
@ -185,6 +186,17 @@ TEST(IteratorTest, TruncatingIterator) {
|
||||
EXPECT_EQ(it.base(), p + 1);
|
||||
}
|
||||
|
||||
TEST(IteratorTest, TruncatingBackInserter) {
|
||||
std::string buffer;
|
||||
auto bi = std::back_inserter(buffer);
|
||||
fmt::internal::truncating_iterator<decltype(bi)> it(bi, 2);
|
||||
*it++ = '4';
|
||||
*it++ = '2';
|
||||
*it++ = '1';
|
||||
EXPECT_EQ(buffer.size(), 2);
|
||||
EXPECT_EQ(buffer, "42");
|
||||
}
|
||||
|
||||
TEST(MemoryBufferTest, Ctor) {
|
||||
basic_memory_buffer<char, 123> buffer;
|
||||
EXPECT_EQ(static_cast<size_t>(0), buffer.size());
|
||||
|
Loading…
Reference in New Issue
Block a user