mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-31 03:07:36 +02:00
Implement format_to_n
This commit is contained in:
@ -702,7 +702,7 @@ FMT_CONSTEXPR const Char *pointer_from(null_terminating_iterator<Char> it) {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
class counting_iterator {
|
class counting_iterator {
|
||||||
private:
|
private:
|
||||||
std::size_t& count_;
|
std::size_t* count_;
|
||||||
mutable T blackhole_;
|
mutable T blackhole_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -712,16 +712,10 @@ class counting_iterator {
|
|||||||
typedef T* pointer;
|
typedef T* pointer;
|
||||||
typedef T& reference;
|
typedef T& reference;
|
||||||
|
|
||||||
explicit counting_iterator(std::size_t &count): count_(count) {}
|
explicit counting_iterator(std::size_t &count): count_(&count) {}
|
||||||
counting_iterator(const counting_iterator &other): count_(other.count_) {}
|
|
||||||
|
|
||||||
counting_iterator& operator=(const counting_iterator &other) {
|
|
||||||
count_ = other.count_;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
counting_iterator& operator++() {
|
counting_iterator& operator++() {
|
||||||
++count_;
|
++*count_;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -730,6 +724,41 @@ class counting_iterator {
|
|||||||
T &operator*() const { return blackhole_; }
|
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;
|
||||||
|
|
||||||
|
OutputIt out_;
|
||||||
|
std::size_t limit_;
|
||||||
|
std::size_t *count_;
|
||||||
|
mutable typename traits::value_type blackhole_;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
truncating_iterator(OutputIt out, std::size_t limit, std::size_t &count)
|
||||||
|
: out_(out), limit_(limit), count_(&count) {}
|
||||||
|
|
||||||
|
OutputIt base() const { return out_; }
|
||||||
|
|
||||||
|
truncating_iterator& operator++() {
|
||||||
|
if ((*count_)++ < limit_)
|
||||||
|
++out_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
truncating_iterator operator++(int) { return ++*this; }
|
||||||
|
|
||||||
|
reference operator*() const { return *count_ < limit_ ? *out_ : blackhole_; }
|
||||||
|
};
|
||||||
|
|
||||||
// Returns true if value is negative, false otherwise.
|
// Returns true if value is negative, false otherwise.
|
||||||
// Same as (value < 0) but doesn't produce warnings if T is an unsigned type.
|
// Same as (value < 0) but doesn't produce warnings if T is an unsigned type.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -3374,6 +3403,22 @@ inline typename std::enable_if<
|
|||||||
return vformat_to(out, format_str, make_args(args...));
|
return vformat_to(out, format_str, make_args(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename OutputIt>
|
||||||
|
struct format_to_n_result {
|
||||||
|
OutputIt out;
|
||||||
|
std::size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename OutputIt, typename... Args>
|
||||||
|
inline format_to_n_result<OutputIt> format_to_n(
|
||||||
|
OutputIt out, std::size_t n, string_view format_str, const Args & ... args) {
|
||||||
|
typedef internal::truncating_iterator<OutputIt> It;
|
||||||
|
std::size_t count = 0;
|
||||||
|
auto it = vformat_to(It(out, n, count), format_str,
|
||||||
|
*make_args<typename context_t<It>::type>(args...));
|
||||||
|
return {it.base(), count};
|
||||||
|
}
|
||||||
|
|
||||||
inline std::string vformat(string_view format_str, format_args args) {
|
inline std::string vformat(string_view format_str, format_args args) {
|
||||||
memory_buffer buffer;
|
memory_buffer buffer;
|
||||||
vformat_to(buffer, format_str, args);
|
vformat_to(buffer, format_str, args);
|
||||||
|
@ -1505,6 +1505,14 @@ TEST(FormatTest, OutputSize) {
|
|||||||
EXPECT_EQ(2u, fmt::count("{}", 42));
|
EXPECT_EQ(2u, fmt::count("{}", 42));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(FormatTest, FormatToN) {
|
||||||
|
char buffer[4];
|
||||||
|
buffer[3] = 'x';
|
||||||
|
auto result = fmt::format_to_n(buffer, 3, "{}", 12345);
|
||||||
|
EXPECT_EQ(5u, result.size);
|
||||||
|
EXPECT_EQ("123x", fmt::string_view(buffer, 4));
|
||||||
|
}
|
||||||
|
|
||||||
#if FMT_USE_CONSTEXPR
|
#if FMT_USE_CONSTEXPR
|
||||||
struct test_arg_id_handler {
|
struct test_arg_id_handler {
|
||||||
enum result { NONE, EMPTY, INDEX, NAME, ERROR };
|
enum result { NONE, EMPTY, INDEX, NAME, ERROR };
|
||||||
|
Reference in New Issue
Block a user