header_utils
Loading...
Searching...
No Matches
buffers.h
1
4
5#pragma once
6
7#include "bytes.h"
8#include "expected.h"
9#include "min-cpp-version/cpp20.h"
10
11namespace ghassanpl
12{
13 namespace detail
14 {
15 template <typename BUFFER>
16 consteval auto deduce_buffer_element_type() noexcept
17 {
18 if constexpr (requires { typename BUFFER::value_type; })
19 return std::type_identity<typename BUFFER::value_type>{};
20 else if constexpr (requires { typename BUFFER::char_type; })
21 return std::type_identity<typename BUFFER::char_type>{};
22 }
23 }
24
30
33
35 template <typename BUFFER>
36 using buffer_element_type = typename decltype(detail::deduce_buffer_element_type<BUFFER>())::type;
37
39 template <typename BUFFER, typename T>
40 bool buffer_append(BUFFER&& buffer, T&& val)
41 {
42 if constexpr (requires { buffer.append(val); })
43 {
44 buffer.append(val);
45 return true;
46 }
47 else if constexpr (requires { buffer.push_back(val); })
48 {
49 buffer.push_back(val);
50 return true;
51 }
52 else if constexpr (requires { buffer.insert(buffer.end(), val); })
53 {
54 buffer.insert(buffer.end(), val);
55 return true;
56 }
57 else if constexpr (requires { buffer.put(val); })
58 {
59 buffer.put(val);
60 return true;
61 }
62 else
63 {
64 static_assert(!always_false<T>, "buffer cannot be appended with this value type - buffer_append might need to be specialized");
65 return false;
66 }
67 }
68
70 template <typename BUFFER, typename ELEMENT_VALUE>
71 concept output_buffer = requires (BUFFER buffer, ELEMENT_VALUE val) {
72 ::ghassanpl::buffer_append(buffer, val);
73 };
74
76 template <typename BUFFER>
77 bool buffer_reserve(BUFFER& buffer, size_t additional)
78 {
79 if constexpr (requires { buffer.reserve(std::ranges::size(buffer) + additional); })
80 {
81 buffer.reserve(std::ranges::size(buffer) + additional);
82 return true;
83 }
84 else
85 return false;
86 }
87
89 template <typename BUFFER, typename RANGE>
90 requires output_buffer<BUFFER, std::ranges::range_value_t<RANGE>>
91 size_t buffer_append_range(BUFFER& buffer, RANGE&& range)
92 {
93 if constexpr (std::ranges::sized_range<RANGE>)
94 buffer_reserve(buffer, std::ranges::size(range));
95
96 if constexpr (requires { buffer.append(std::to_address(std::ranges::begin(range)), std::ranges::size(range)); } && std::ranges::sized_range<RANGE>)
97 {
98 const auto size = std::ranges::size(range);
99 buffer.append(std::to_address(std::ranges::begin(range)), size);
100 return size;
101 }
102 else if constexpr (requires { buffer.write(std::to_address(std::ranges::begin(range)), std::ranges::size(range)); } && std::ranges::sized_range<RANGE>)
103 {
104 const auto size = std::ranges::size(range);
106 buffer.write(std::to_address(std::ranges::begin(range)), size);
109 return size;
110 }
111 else
112 {
113 size_t count = 0;
114 for (auto&& value : std::forward<RANGE>(range))
115 {
116 if (!buffer_append(buffer, value))
117 break;
118 ++count;
119 }
120 return count;
121 }
122 }
123
125 template <typename BUFFER, typename CHAR_TYPE>
126 requires output_buffer<BUFFER, CHAR_TYPE>
127 size_t buffer_append_cstring_ptr(BUFFER& buffer, const CHAR_TYPE* cstr)
128 {
129 return buffer_append_range(buffer, cstr, cstr + std::char_traits<CHAR_TYPE>::length(cstr));
130 }
131
133 template <typename BUFFER, typename CHAR_TYPE>
134 requires output_buffer<BUFFER, CHAR_TYPE>
135 size_t buffer_append_cstring_ptr(BUFFER& buffer, const CHAR_TYPE* cstr, size_t max_len)
136 {
137 return buffer_append_range(buffer, cstr, cstr + std::min(max_len, std::char_traits<CHAR_TYPE>::length(cstr)));
138 }
139
141 template <typename BUFFER, size_t N, typename CHAR_TYPE>
142 requires output_buffer<BUFFER, CHAR_TYPE>
143 size_t buffer_append_cstring(BUFFER& buffer, const CHAR_TYPE(&cstr)[N])
144 {
145 return buffer_append_range(buffer, std::span{ cstr, cstr + (N - 1) });
146 }
147
149 template <typename BUFFER, typename ELEMENT_TYPE = buffer_element_type<BUFFER>>
150 requires output_buffer<BUFFER, ELEMENT_TYPE>
151 size_t buffer_append_varint(BUFFER& buffer, std::integral auto oval)
152 {
153 auto val = std::bit_cast<std::make_unsigned_t<decltype(oval)>>(oval);
154 if constexpr (std::is_signed_v<decltype(val)>)
155 val = (oval < 0) ? ((std::bit_cast<std::make_unsigned_t<decltype(oval)>>(-oval) << 1) | 1) : (val << 1);
156 size_t result = 0;
157 while (val >= 128)
158 {
159 result += buffer_append(buffer, uint8_t(0x80 | (val & 0x7f)));
160 val >>= 7;
161 }
162 result += buffer_append(buffer, uint8_t(val));
163 return result;
164 }
165
167 template <typename BUFFER, typename ELEMENT_TYPE = buffer_element_type<BUFFER>>
168 requires output_buffer<BUFFER, ELEMENT_TYPE>
169 size_t buffer_append_utf8(BUFFER& buffer, char32_t cp)
170 {
171 size_t result = 0;
172 if (cp < 0x80ULL)
173 {
174 result += buffer_append(buffer, static_cast<ELEMENT_TYPE>(cp));
175 }
176 else if (cp < 0x800ULL) {
177 result += buffer_append(buffer, static_cast<ELEMENT_TYPE>((cp >> 6) | 0xc0));
178 result += buffer_append(buffer, static_cast<ELEMENT_TYPE>((cp & 0x3f) | 0x80));
179 }
180 else if (cp < 0x10000ULL) {
181 result += buffer_append(buffer, static_cast<ELEMENT_TYPE>((cp >> 12) | 0xe0));
182 result += buffer_append(buffer, static_cast<ELEMENT_TYPE>(((cp >> 6) & 0x3f) | 0x80));
183 result += buffer_append(buffer, static_cast<ELEMENT_TYPE>((cp & 0x3f) | 0x80));
184 }
185 else {
186 result += buffer_append(buffer, static_cast<ELEMENT_TYPE>((cp >> 18) | 0xf0));
187 result += buffer_append(buffer, static_cast<ELEMENT_TYPE>(((cp >> 12) & 0x3f) | 0x80));
188 result += buffer_append(buffer, static_cast<ELEMENT_TYPE>(((cp >> 6) & 0x3f) | 0x80));
189 result += buffer_append(buffer, static_cast<ELEMENT_TYPE>((cp & 0x3f) | 0x80));
190 }
191
192 return result;
193 }
194
197 template <typename BUFFER, typename STRING_TYPE, typename ELEMENT_TYPE = buffer_element_type<BUFFER>>
198 requires output_buffer<BUFFER, ELEMENT_TYPE> && std::ranges::range<STRING_TYPE> && std::same_as<std::ranges::range_value_t<STRING_TYPE>, char32_t>
199 size_t buffer_append_utf8(BUFFER& buffer, STRING_TYPE&& str)
200 {
201 size_t count = 0;
202 for (auto cp : str)
203 count += buffer_append_utf8(buffer, cp);
204 return count;
205 }
206
210 template <typename BUFFER, typename POD>
211 requires std::is_trivially_copyable_v<POD> && bytelike<buffer_element_type<BUFFER>>
212 size_t buffer_append_pod(BUFFER& buffer, POD const& pod)
213 {
215 }
216
217 /*
219 template <typename BUFFER, typename CALLBACK>
220 requires std::invocable<CALLBACK, size_t, std::string_view, BUFFER&>
221 void callback_format_to(BUFFER& buffer, std::string_view fmt, CALLBACK&& callback)
222 {
224 size_t aid = 0;
225 while (!fmt.empty())
226 {
227 auto text = consume_until(fmt, '{');
228 buffer_append_range(buffer, text);
229 if (fmt.empty())
230 continue;
231 std::ignore = consume(fmt, '{');
232
233 if (consume(fmt, '{'))
234 {
235 buffer_append_range(buffer, '{');
236 continue;
237 }
238 else
239 {
240 std::string fmt_clause_str = "{";
241 auto fmt_clause = string_ops::consume_until_delim(fmt, '}');
242 if (!string_ops::consume_at_end(fmt_clause, '}'))
243 throw std::format_error("missing '}' in format string");
244 if (!fmt_clause.empty())
245 {
246 auto num = string_ops::consume_until(fmt_clause, ':');
247 if (!num.empty())
248 aid = string_ops::stoull(num);
249 fmt_clause_str += fmt_clause;
250 }
251 fmt_clause_str += '}';
252 callback(aid, std::string_view{ fmt_clause_str }, buffer);
253 ++aid;
254 }
255 }
256 }
257 */
258
260
261 enum class buffer_compression_error_type
262 {
263 unknown_error,
264 invalid_options,
265 //no_input,
266 //no_more_space_in_output_buffer,
267 };
268
269 struct buffer_compression_error
270 {
271 buffer_compression_error_type type{};
272 std::string description;
273 };
274
275 template <typename T>
276 using buffer_compression_result = expected<T, buffer_compression_error>;
277
278 template <typename COMPRESSOR>
279 buffer_compression_result<void> compressor_restart(COMPRESSOR& comp) = delete;
280 template <typename COMPRESSOR, typename BUFFER>
281 buffer_compression_result<void> compressor_compress_fragment(COMPRESSOR& comp, bytelike_range auto&& input_range, BUFFER& output_buffer) = delete;
282 template <typename COMPRESSOR, typename BUFFER>
283 buffer_compression_result<void> compressor_finalize(COMPRESSOR& comp, BUFFER& output_buffer) = delete;
284
285 /*
286 template <typename T>
287 concept compressor = requires (T & comp, std::span<char const> in_range, std::string out_range) {
288 { compressor_restart(comp) } -> std::convertible_to<buffer_compression_result<void>>;
289 { compressor_compress_fragment(comp, in_range, out_range) } -> std::convertible_to<buffer_compression_result<void>>;
290 { compressor_finalize(comp, out_range) } -> std::convertible_to<buffer_compression_result<void>>;
291 };
292 */
293
294 template <typename BUFFER, bytelike_range RANGE, typename COMPRESSOR>
295 buffer_compression_result<void> buffer_append_compressed(BUFFER& buffer, RANGE&& input_range, COMPRESSOR& comp)
296 {
297 //static_assert(compressor<COMPRESSOR>, "comp must be a compressor");
298 return compressor_restart(comp)
299 .and_then([&] { return compressor_compress_fragment(comp, input_range, buffer); })
300 .and_then([&] { return compressor_finalize(comp, buffer); });
301 }
302}
A range of bytelikes.
Definition bytes.h:35
Checks if an element value is appendable to a buffer.
Definition buffers.h:71
bool buffer_append(BUFFER &&buffer, T &&val)
Primary function to append a value (preferably the buffer element type) to the buffer.
Definition buffers.h:40
size_t buffer_append_pod(BUFFER &buffer, POD const &pod)
Appends a POD value's internal object representation to a buffer.
Definition buffers.h:212
bool buffer_reserve(BUFFER &buffer, size_t additional)
Reserves additional elements in the buffer, if possible.
Definition buffers.h:77
size_t buffer_append_cstring(BUFFER &buffer, const CHAR_TYPE(&cstr)[N])
Appends characters in the cstr literal array to the buffer.
Definition buffers.h:143
size_t buffer_append_varint(BUFFER &buffer, std::integral auto oval)
Appends a variable number of uint8_ts to the buffer that encode the value oval in a minimal amount of...
Definition buffers.h:151
typename decltype(detail::deduce_buffer_element_type< BUFFER >())::type buffer_element_type
Resolves to the destination element type of the buffer.
Definition buffers.h:36
size_t buffer_append_range(BUFFER &buffer, RANGE &&range)
Appends elements in the range to the buffer.
Definition buffers.h:91
size_t buffer_append_cstring_ptr(BUFFER &buffer, const CHAR_TYPE *cstr)
Appends characters in the cstr to the buffer.
Definition buffers.h:127
size_t buffer_append_utf8(BUFFER &buffer, char32_t cp)
Appends UTF-8 codeunits that represent the Unicode code-point cp to the buffer. Assumes the codepoint...
Definition buffers.h:169
std::span< TO > as_bytelikes(std::span< FROM, N > elements) noexcept
Converts a span of trivial values to a span of bytelike s.
Definition bytes.h:40
Primary namespace for everything in this library.
Definition align+rec2.h:10