Clingo
Loading...
Searching...
No Matches
print.hh
1#pragma once
2
3#include <algorithm>
4#include <cassert>
5#include <charconv>
6#include <cstring>
7#include <span>
8#include <string>
9#include <string_view>
10#include <vector>
11
12namespace CppClingo::Util {
13
16
25 public:
27 using value_type = char;
28
30 OutputBuffer(FILE *out = nullptr) : out_{out} {}
31
35 void flush() {
36 if (out_ != nullptr) {
37 fwrite(buf_.data(), sizeof(char), size_, out_);
38 fflush(out_);
39 size_ = 0;
40 }
41 }
42
46 void endl() {
47 constexpr auto n = 8192;
48 if (out_ != nullptr && size_ > n) {
49 fwrite(buf_.data(), sizeof(char), size_, out_);
50 size_ = 0;
51 }
52 }
53
55 [[nodiscard]] auto size() const -> size_t { return static_cast<size_t>(size_); }
56
58 [[nodiscard]] auto empty() const -> bool { return size_ == 0; }
59
61 [[nodiscard]] auto view() const -> std::string_view {
62 return std::string_view{buf_.data(), static_cast<size_t>(size_)};
63 }
64
66 [[nodiscard]] auto span() -> std::span<char> { return std::span{buf_.data(), static_cast<size_t>(size_)}; }
67
69 [[nodiscard]] auto str() const -> std::string { return std::string{buf_.data(), static_cast<size_t>(size_)}; }
70
72 [[nodiscard]] auto c_str() -> char const * {
73 *ensure_(1) = '\0';
74 return buf_.data();
75 }
76
78 auto reset() -> OutputBuffer & {
79 size_ = 0;
80 return *this;
81 }
82
84 auto release() -> std::vector<char> {
85 buf_.resize(size_);
86 buf_.emplace_back('\0');
87 auto ret = std::move(buf_);
88 buf_.clear();
89 size_ = 0;
90 return ret;
91 }
92
94 void append(char const *str) {
95 auto n = static_cast<std::ptrdiff_t>(std::strlen(str));
96 std::copy(str, std::next(str, n), ensure_(n));
97 size_ += n;
98 }
99
101 void append(std::string_view str) {
102 auto n = static_cast<std::ptrdiff_t>(str.length());
103 std::ranges::copy(str, ensure_(n));
104 size_ += n;
105 }
106
108 void append(char c) {
109 *ensure_(1) = c;
110 ++size_;
111 }
112
114 void push_back(char c) { append(c); }
115
117 void pop() { --size_; }
118
120 template <std::integral T> void append(T num, int base = 10) { // NOLINT
121 constexpr auto n = 256;
122 auto *end = ensure_(n);
123 auto res = std::to_chars(end, limit_(), num, base);
124 size_ += res.ptr - end;
125 }
126
130 auto reserve(std::ptrdiff_t n) -> std::span<char> {
131 auto *begin = ensure_(n);
132 size_ += n;
133 return {begin, std::next(begin, n)};
134 }
135
139 void trim_zero(std::ptrdiff_t len) {
140 auto sp = std::span{buf_.data(), static_cast<size_t>(size_)};
141 auto ie = sp.end();
142 auto ib = sp.begin() + (size_ - len);
143 auto it = std::find(ib, ie, '\0');
144 size_ -= ie - it;
145 }
146
148 template <std::integral T> friend auto operator<<(OutputBuffer &out, T num) -> OutputBuffer & {
149 out.append(num);
150 return out;
151 }
152
154 friend auto operator<<(OutputBuffer &out, char c) -> OutputBuffer & {
155 out.append(c);
156 return out;
157 }
158
160 friend auto operator<<(OutputBuffer &out, std::string_view str) -> OutputBuffer & {
161 out.append(str);
162 return out;
163 }
164
166 friend auto operator<<(OutputBuffer &out, double value) -> OutputBuffer & {
167 static constexpr std::ptrdiff_t n = 32;
168 auto *begin = out.ensure_(n);
169 auto *end = std::next(begin, n);
170 auto [res, ec] = std::to_chars(begin, end, value);
171 out.size_ += std::distance(begin, res);
172 return out;
173 }
174
176 friend auto operator<<(OutputBuffer &out, char const *str) -> OutputBuffer & {
177 out.append(str);
178 return out;
179 }
180
181 private:
182 auto limit_() -> char * { return std::next(buf_.data(), static_cast<std::ptrdiff_t>(buf_.size())); }
183
184 auto ensure_(std::ptrdiff_t n) -> char * {
185 auto m = size_ + n;
186 assert(n >= 0 && m >= 0);
187 if (buf_.size() < static_cast<size_t>(m)) {
188 buf_.reserve(2 * static_cast<size_t>(m));
189 buf_.resize(buf_.capacity());
190 }
191 return std::next(buf_.data(), size_);
192 }
193
194 std::vector<char> buf_;
195 std::ptrdiff_t size_ = 0;
196 FILE *out_;
197};
198
199namespace Detail {
200
202struct PrintSelf {
204 template <class Out> void operator()(Out &out, auto const &x) { out << x; }
205};
206
208template <class It, class F> class PrintRange {
209 public:
211 template <class A>
212 PrintRange(It first, It last, char const *sep, A &&fun)
213 : first_{first}, last_{last}, sep_{sep}, fun_{std::forward<A>(fun)} {}
215 template <class Out> friend auto operator<<(Out &out, PrintRange rng) -> Out & {
216 if (rng.first_ != rng.last_) {
217 rng.fun_(out, *rng.first_);
218 for (++rng.first_; rng.first_ != rng.last_; ++rng.first_) {
219 out << rng.sep_;
220 rng.fun_(out, *rng.first_);
221 }
222 }
223 return out;
224 }
225
226 private:
227 It first_;
228 It last_;
229 char const *sep_;
230 [[no_unique_address]] F fun_;
231};
232
233template <class It, class F> PrintRange(It, It, char const *, F &&) -> PrintRange<It, std::unwrap_ref_decay_t<F>>;
234
236template <class F> class PrintFun {
237 public:
239 template <class A> PrintFun([[maybe_unused]] int tag, A &&fun) : fun_{std::forward<A>(fun)} {}
241 template <class Out> friend auto operator<<(Out &out, PrintFun x) -> Out & {
242 x.fun_(out);
243 return out;
244 }
245
246 private:
247 F fun_;
248};
249
250template <class F> PrintFun(int, F &&) -> PrintFun<std::unwrap_ref_decay_t<F>>;
251
253class PrintQuoted {
254 public:
256 PrintQuoted(std::string_view str, bool fstring) : str_{str}, fstring_{fstring} {}
258 template <class Out> friend auto operator<<(Out &out, PrintQuoted x) -> Out & {
259 if (!x.fstring_) {
260 out << '"';
261 }
262 for (auto c : x.str_) {
263 if (c == '\\') {
264 out << "\\\\";
265 } else if (x.fstring_ && c == '{') {
266 out << "{{";
267 } else if (x.fstring_ && c == '}') {
268 out << "}}";
269 } else if (c == '\n') {
270 out << "\\n";
271 } else if (c == '\t') {
272 out << "\\t";
273 } else if (c == '"') {
274 out << "\\\"";
275 } else {
276 out << c;
277 }
278 }
279 if (!x.fstring_) {
280 out << '"';
281 }
282 return out;
283 }
284
285 private:
286 std::string_view str_;
287 bool fstring_ = false;
288};
289
290} // namespace Detail
291
293class fill {
294 public:
296 fill(size_t n, char c = ' ') : n_{n}, c_{c} {}
299 std::ranges::fill(out.reserve(static_cast<std::ptrdiff_t>(x.n_)), x.c_);
300 return out;
301 }
302
303 private:
304 size_t n_;
305 char c_;
306};
307
309template <class F> auto p_fun(F &&fun) {
310 return Detail::PrintFun(0, std::forward<F>(fun));
311}
312
314template <class T, class F> auto p_range(T const &rng, char const *sep, F &&fun) {
315 using std::begin, std::end;
316 return Detail::PrintRange{begin(rng), end(rng), sep, std::forward<F>(fun)};
317}
318
320template <class T> auto p_range(T const &rng) {
321 return p_range(rng, ",", Detail::PrintSelf{});
322}
323
325template <class T, class F> auto p_range(T const &rng, F &&fun) {
326 return p_range(rng, ",", std::forward<F>(fun));
327}
328
330template <class T> auto p_range(T const &rng, char const *sep) {
331 return p_range(rng, sep, Detail::PrintSelf{});
332}
333
335inline auto p_quoted(std::string_view str, bool fstring = false) {
336 return Detail::PrintQuoted{str, fstring};
337}
338
340
341} // namespace CppClingo::Util
Create an output buffer that bears some similarities with C++'s iostreams.
Definition print.hh:24
auto size() const -> size_t
Get the number of bytes currently stored in the buffer.
Definition print.hh:55
auto release() -> std::vector< char >
Empty the buffer and return a vector with the previous content.
Definition print.hh:84
void append(T num, int base=10)
Append an integral to the buffer.
Definition print.hh:120
friend auto operator<<(OutputBuffer &out, T num) -> OutputBuffer &
Append the given integral to the buffer.
Definition print.hh:148
auto span() -> std::span< char >
Get a char span of the current buffer content.
Definition print.hh:66
void flush()
Flush the buffer.
Definition print.hh:35
auto empty() const -> bool
Check if the buffer is currently emtpy.
Definition print.hh:58
auto view() const -> std::string_view
Get a string view of the current buffer content.
Definition print.hh:61
void append(char c)
Append a char to the buffer.
Definition print.hh:108
auto c_str() -> char const *
Get a C string with the current buffer content.
Definition print.hh:72
friend auto operator<<(OutputBuffer &out, double value) -> OutputBuffer &
Append the given double to the buffer.
Definition print.hh:166
friend auto operator<<(OutputBuffer &out, char const *str) -> OutputBuffer &
Append the given string to the buffer.
Definition print.hh:176
void pop()
Pop a char from the buffer.
Definition print.hh:117
void append(std::string_view str)
Append a string to the buffer.
Definition print.hh:101
void trim_zero(std::ptrdiff_t len)
Trim trailing zeros.
Definition print.hh:139
friend auto operator<<(OutputBuffer &out, std::string_view str) -> OutputBuffer &
Append the given string to the buffer.
Definition print.hh:160
auto str() const -> std::string
Get a string with the current buffer content.
Definition print.hh:69
auto reserve(std::ptrdiff_t n) -> std::span< char >
Append n bytes at the end of the buffer.
Definition print.hh:130
void endl()
Flush the buffer if it has a predefined minimum size.
Definition print.hh:46
void push_back(char c)
Alias for append(char) to support std::back_inserter.
Definition print.hh:114
OutputBuffer(FILE *out=nullptr)
Construt the buffer with an optional file handle.
Definition print.hh:30
friend auto operator<<(OutputBuffer &out, char c) -> OutputBuffer &
Append the given char to the buffer.
Definition print.hh:154
auto reset() -> OutputBuffer &
Empty the buffer.
Definition print.hh:78
char value_type
The value type of the buffer.
Definition print.hh:27
void append(char const *str)
Append a string to the buffer.
Definition print.hh:94
Helper for iostreams to fill with a fixed number of characters.
Definition print.hh:293
fill(size_t n, char c=' ')
The constructor.
Definition print.hh:296
friend auto operator<<(CppClingo::Util::OutputBuffer &out, fill const &x) -> CppClingo::Util::OutputBuffer &
Operator to print the fill helper.
Definition print.hh:298
auto operator<<(std::ostream &out, Sign sign) -> std::ostream &
Output the given sign.
auto p_quoted(std::string_view str, bool fstring=false)
Quote and print the given string.
Definition print.hh:335
auto p_fun(F &&fun)
Print with a function.
Definition print.hh:309
auto p_range(T const &rng, char const *sep, F &&fun)
Print a range with a separator.
Definition print.hh:314