blob: 0a57d003d704018c98ec5b723c783accbf745e27 [file] [log] [blame]
// Copyright 2024 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_LIB_STDFORMAT_INTERNAL_PRINT_H_
#define SRC_LIB_STDFORMAT_INTERNAL_PRINT_H_
#include <cstdio>
#include <format>
#include <iterator>
#include <span>
namespace cpp23::internal {
class stream_output_iterator {
public:
using iterator_category = std::output_iterator_tag;
using value_type = char;
using difference_type = std::ptrdiff_t;
using pointer = char*;
using reference = char&;
explicit stream_output_iterator(std::FILE* stream, std::span<char> buffer)
: stream_(stream), buffer_(buffer) {}
stream_output_iterator(stream_output_iterator&& other) noexcept
: stream_(other.stream_), buffer_(other.buffer_), index_(other.index_) {}
stream_output_iterator& operator=(stream_output_iterator&& other) noexcept {
stream_ = other.stream_;
buffer_ = other.buffer_;
index_ = other.index_;
return *this;
}
stream_output_iterator(const stream_output_iterator& other) noexcept = default;
stream_output_iterator& operator=(const stream_output_iterator& other) noexcept = delete;
stream_output_iterator& operator=(const char& ch) {
buffer_[index_] = ch;
return *this;
}
reference operator*() { return buffer_[index_]; }
stream_output_iterator& operator++() {
index_++;
if (index_ == buffer_.size()) {
fwrite(buffer_.data(), 1, buffer_.size(), stream_);
index_ = 0;
}
return *this;
}
stream_output_iterator operator++(int) {
auto tmp = *this;
++*this;
return tmp;
}
size_t index() const { return index_; }
private:
std::FILE* stream_;
std::span<char> buffer_;
size_t index_ = 0;
};
// This function is neither vprint_unicode nor vprint_unicode_buffered exactly, and thus not being
// made public. The former relies on stdio for any buffering. The latter guarantees exactly one
// stdio write per call. This one splits the difference by doing as few stdio writes as possible
// with the chosen buffer size while not requiring dynamic allocation.
inline void vprint(std::FILE* stream, std::string_view fmt, std::format_args args) {
constexpr size_t kBufferSize = 256;
std::array<char, kBufferSize> buffer = {};
size_t index = std::vformat_to(stream_output_iterator(stream, buffer), fmt, args).index();
if (index > 0) {
fwrite(buffer.data(), 1, index, stream);
}
}
} // namespace cpp23::internal
#endif // SRC_LIB_STDFORMAT_INTERNAL_PRINT_H_