Skip to content

Commit

Permalink
Optimize compiled format_to_n
Browse files Browse the repository at this point in the history
  • Loading branch information
vitaut committed Jul 20, 2023
1 parent 388bc29 commit 436c131
Show file tree
Hide file tree
Showing 2 changed files with 4 additions and 113 deletions.
85 changes: 4 additions & 81 deletions include/fmt/compile.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,84 +19,6 @@ FMT_CONSTEXPR inline counting_iterator copy_str(InputIt begin, InputIt end,
return it + (end - begin);
}

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;
FMT_UNCHECKED_ITERATOR(truncating_iterator_base);

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.
class compiled_string {};

Expand Down Expand Up @@ -568,9 +490,10 @@ template <typename OutputIt, typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n,
const S& format_str, Args&&... args) {
auto it = fmt::format_to(detail::truncating_iterator<OutputIt>(out, n),
format_str, std::forward<Args>(args)...);
return {it.base(), it.count()};
using traits = detail::fixed_buffer_traits;
auto buf = detail::iterator_buffer<OutputIt, char, traits>(out, n);
format_to(std::back_inserter(buf), format_str, std::forward<Args>(args)...);
return {buf.out(), buf.count()};
}

template <typename S, typename... Args,
Expand Down
32 changes: 0 additions & 32 deletions test/compile-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,38 +21,6 @@ TEST(iterator_test, counting_iterator) {
EXPECT_EQ((it + 41).count(), 42);
}

TEST(iterator_test, truncating_iterator) {
char* p = nullptr;
auto it = fmt::detail::truncating_iterator<char*>(p, 3);
auto prev = it++;
EXPECT_EQ(prev.base(), p);
EXPECT_EQ(it.base(), p + 1);
}

TEST(iterator_test, truncating_iterator_default_construct) {
auto it = fmt::detail::truncating_iterator<char*>();
EXPECT_EQ(nullptr, it.base());
EXPECT_EQ(std::size_t{0}, it.count());
}

#ifdef __cpp_lib_ranges
TEST(iterator_test, truncating_iterator_is_output_iterator) {
static_assert(
std::output_iterator<fmt::detail::truncating_iterator<char*>, char>);
}
#endif

TEST(iterator_test, truncating_back_inserter) {
auto buffer = std::string();
auto bi = std::back_inserter(buffer);
auto it = fmt::detail::truncating_iterator<decltype(bi)>(bi, 2);
*it++ = '4';
*it++ = '2';
*it++ = '1';
EXPECT_EQ(buffer.size(), 2);
EXPECT_EQ(buffer, "42");
}

TEST(compile_test, compile_fallback) {
// FMT_COMPILE should fallback on runtime formatting when `if constexpr` is
// not available.
Expand Down

0 comments on commit 436c131

Please sign in to comment.