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 OutputBuffer(FILE *out = nullptr) : out_{out} {}
28
32 void flush() {
33 if (out_ != nullptr) {
34 fwrite(buf_.data(), sizeof(char), size_, out_);
35 fflush(out_);
36 size_ = 0;
37 }
38 }
39
43 void endl() {
44 constexpr auto n = 8192;
45 if (out_ != nullptr && size_ > n) {
46 fwrite(buf_.data(), sizeof(char), size_, out_);
47 size_ = 0;
48 }
49 }
50
52 [[nodiscard]] auto size() const -> size_t { return static_cast<size_t>(size_); }
53
55 [[nodiscard]] auto empty() const -> bool { return size_ == 0; }
56
58 [[nodiscard]] auto view() const -> std::string_view {
59 return std::string_view{buf_.data(), static_cast<size_t>(size_)};
60 }
61
63 [[nodiscard]] auto str() const -> std::string { return std::string{buf_.data(), static_cast<size_t>(size_)}; }
64
66 [[nodiscard]] auto c_str() -> char const * {
67 *ensure_(1) = '\0';
68 return buf_.data();
69 }
70
72 auto reset() -> OutputBuffer & {
73 size_ = 0;
74 return *this;
75 }
76
78 auto release() -> std::vector<char> {
79 buf_.resize(size_);
80 buf_.emplace_back('\0');
81 auto ret = std::move(buf_);
82 buf_.clear();
83 size_ = 0;
84 return ret;
85 }
86
88 void append(char const *str) {
89 auto n = static_cast<std::ptrdiff_t>(std::strlen(str));
90 std::copy(str, std::next(str, n), ensure_(n));
91 size_ += n;
92 }
93
95 void append(std::string_view str) {
96 auto n = static_cast<std::ptrdiff_t>(str.length());
97 std::ranges::copy(str, ensure_(n));
98 size_ += n;
99 }
100
102 void append(char c) {
103 *ensure_(1) = c;
104 ++size_;
105 }
106
108 void pop() { --size_; }
109
111 template <std::integral T> void append(T num) {
112 constexpr auto n = 128;
113 auto *end = ensure_(n);
114 auto res = std::to_chars(end, limit_(), num);
115 size_ += res.ptr - end;
116 }
117
121 auto reserve(std::ptrdiff_t n) -> std::span<char> {
122 auto *begin = ensure_(n);
123 size_ += n;
124 return {begin, std::next(begin, n)};
125 }
126
130 void trim_zero(std::ptrdiff_t len) {
131 auto sp = std::span{buf_.data(), static_cast<size_t>(size_)};
132 auto ie = sp.end();
133 auto ib = sp.begin() + (size_ - len);
134 auto it = std::find(ib, ie, '\0');
135 size_ -= ie - it;
136 }
137
139 template <std::integral T> friend auto operator<<(OutputBuffer &out, T num) -> OutputBuffer & {
140 out.append(num);
141 return out;
142 }
143
145 friend auto operator<<(OutputBuffer &out, char c) -> OutputBuffer & {
146 out.append(c);
147 return out;
148 }
149
151 friend auto operator<<(OutputBuffer &out, std::string_view str) -> OutputBuffer & {
152 out.append(str);
153 return out;
154 }
155
157 friend auto operator<<(OutputBuffer &out, double value) -> OutputBuffer & {
158 static constexpr std::ptrdiff_t n = 32;
159 auto *begin = out.ensure_(n);
160 auto *end = std::next(begin, n);
161 auto [res, ec] = std::to_chars(begin, end, value);
162 out.size_ += std::distance(begin, res);
163 return out;
164 }
165
167 friend auto operator<<(OutputBuffer &out, char const *str) -> OutputBuffer & {
168 out.append(str);
169 return out;
170 }
171
172 private:
173 auto limit_() -> char * { return std::next(buf_.data(), static_cast<std::ptrdiff_t>(buf_.size())); }
174
175 auto ensure_(std::ptrdiff_t n) -> char * {
176 auto m = size_ + n;
177 assert(n >= 0 && m >= 0);
178 if (buf_.size() < static_cast<size_t>(m)) {
179 buf_.reserve(2 * static_cast<size_t>(m));
180 buf_.resize(buf_.capacity());
181 }
182 return std::next(buf_.data(), size_);
183 }
184
185 std::vector<char> buf_;
186 std::ptrdiff_t size_ = 0;
187 FILE *out_;
188};
189
190namespace Detail {
191
193struct PrintSelf {
195 template <class Out> void operator()(Out &out, auto const &x) { out << x; }
196};
197
199template <class It, class F> class PrintRange {
200 public:
202 template <class A>
203 PrintRange(It first, It last, char const *sep, A &&fun)
204 : first_{first}, last_{last}, sep_{sep}, fun_{std::forward<A>(fun)} {}
206 template <class Out> friend auto operator<<(Out &out, PrintRange rng) -> Out & {
207 if (rng.first_ != rng.last_) {
208 rng.fun_(out, *rng.first_);
209 for (++rng.first_; rng.first_ != rng.last_; ++rng.first_) {
210 out << rng.sep_;
211 rng.fun_(out, *rng.first_);
212 }
213 }
214 return out;
215 }
216
217 private:
218 It first_;
219 It last_;
220 char const *sep_;
221 [[no_unique_address]] F fun_;
222};
223
224template <class It, class F> PrintRange(It, It, char const *, F &&) -> PrintRange<It, std::unwrap_ref_decay_t<F>>;
225
227template <class F> class PrintFun {
228 public:
230 template <class A> PrintFun([[maybe_unused]] int tag, A &&fun) : fun_{std::forward<A>(fun)} {}
232 template <class Out> friend auto operator<<(Out &out, PrintFun x) -> Out & {
233 x.fun_(out);
234 return out;
235 }
236
237 private:
238 F fun_;
239};
240
241template <class F> PrintFun(int, F &&) -> PrintFun<std::unwrap_ref_decay_t<F>>;
242
244class PrintQuoted {
245 public:
247 PrintQuoted(std::string_view str) : str_{str} {}
249 template <class Out> friend auto operator<<(Out &out, PrintQuoted x) -> Out & {
250 // TODO: in principle there are the codepoints too...
251 out << '"';
252 for (auto c : x.str_) {
253 if (c == '\\') {
254 out << "\\\\";
255 } else if (c == '\n') {
256 out << "\\n";
257 } else if (c == '\t') {
258 out << "\\t";
259 } else if (c == '"') {
260 out << "\\\"";
261 } else {
262 out << c;
263 }
264 }
265 out << '"';
266 return out;
267 }
268
269 private:
270 std::string_view str_;
271};
272
273} // namespace Detail
274
276template <class F> auto p_fun(F &&fun) {
277 return Detail::PrintFun(0, std::forward<F>(fun));
278}
279
281template <class T, class F> auto p_range(T const &rng, char const *sep, F &&fun) {
282 using std::begin, std::end;
283 return Detail::PrintRange{begin(rng), end(rng), sep, std::forward<F>(fun)};
284}
285
287template <class T> auto p_range(T const &rng) {
288 return p_range(rng, ",", Detail::PrintSelf{});
289}
290
292template <class T, class F> auto p_range(T const &rng, F &&fun) {
293 return p_range(rng, ",", std::forward<F>(fun));
294}
295
297template <class T> auto p_range(T const &rng, char const *sep) {
298 return p_range(rng, sep, Detail::PrintSelf{});
299}
300
302inline auto p_quoted(std::string_view str) {
303 return Detail::PrintQuoted{str};
304}
305
307
308} // 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:52
auto release() -> std::vector< char >
Empty the buffer and return a vector with the previous content.
Definition print.hh:78
friend auto operator<<(OutputBuffer &out, T num) -> OutputBuffer &
Append the given integral to the buffer.
Definition print.hh:139
void flush()
Flush the buffer.
Definition print.hh:32
auto empty() const -> bool
Check if the buffer is currently emtpy.
Definition print.hh:55
auto view() const -> std::string_view
Get a string view of the current buffer content.
Definition print.hh:58
void append(char c)
Append a char to the buffer.
Definition print.hh:102
auto c_str() -> char const *
Get a C string with the current buffer content.
Definition print.hh:66
friend auto operator<<(OutputBuffer &out, double value) -> OutputBuffer &
Append the given double to the buffer.
Definition print.hh:157
friend auto operator<<(OutputBuffer &out, char const *str) -> OutputBuffer &
Append the given string to the buffer.
Definition print.hh:167
void pop()
Pop a char from the buffer.
Definition print.hh:108
void append(std::string_view str)
Append a string to the buffer.
Definition print.hh:95
void trim_zero(std::ptrdiff_t len)
Trim trailing zeros.
Definition print.hh:130
friend auto operator<<(OutputBuffer &out, std::string_view str) -> OutputBuffer &
Append the given string to the buffer.
Definition print.hh:151
auto str() const -> std::string
Get a string with the current buffer content.
Definition print.hh:63
auto reserve(std::ptrdiff_t n) -> std::span< char >
Append n bytes at the end of the buffer.
Definition print.hh:121
void endl()
Flush the buffer if it has a predefined minimum size.
Definition print.hh:43
OutputBuffer(FILE *out=nullptr)
Construt the buffer with an optional file handle.
Definition print.hh:27
friend auto operator<<(OutputBuffer &out, char c) -> OutputBuffer &
Append the given char to the buffer.
Definition print.hh:145
auto reset() -> OutputBuffer &
Empty the buffer.
Definition print.hh:72
void append(T num)
Append an integral to the buffer.
Definition print.hh:111
void append(char const *str)
Append a string to the buffer.
Definition print.hh:88
auto operator<<(std::ostream &out, Sign sign) -> std::ostream &
Output the given sign.
auto p_quoted(std::string_view str)
Quote and print the given string.
Definition print.hh:302
auto p_fun(F &&fun)
Print with a function.
Definition print.hh:276
auto p_range(T const &rng, char const *sep, F &&fun)
Print a range with a separator.
Definition print.hh:281