9#include "min-cpp-version/cpp20.h"
15 template <
typename BUFFER>
16 consteval auto deduce_buffer_element_type() noexcept
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>{};
35 template <
typename BUFFER>
39 template <
typename BUFFER,
typename T>
42 if constexpr (
requires { buffer.append(val); })
47 else if constexpr (
requires { buffer.push_back(val); })
49 buffer.push_back(val);
52 else if constexpr (
requires { buffer.insert(buffer.end(), val); })
54 buffer.insert(buffer.end(), val);
57 else if constexpr (
requires { buffer.put(val); })
64 static_assert(!always_false<T>,
"buffer cannot be appended with this value type - buffer_append might need to be specialized");
70 template <
typename BUFFER,
typename ELEMENT_VALUE>
76 template <
typename BUFFER>
79 if constexpr (
requires { buffer.reserve(std::ranges::size(buffer) + additional); })
81 buffer.reserve(std::ranges::size(buffer) + additional);
89 template <
typename BUFFER,
typename RANGE>
90 requires output_buffer<BUFFER, std::ranges::range_value_t<RANGE>>
93 if constexpr (std::ranges::sized_range<RANGE>)
96 if constexpr (
requires { buffer.append(std::to_address(std::ranges::begin(range)), std::ranges::size(range)); } && std::ranges::sized_range<RANGE>)
98 const auto size = std::ranges::size(range);
99 buffer.append(std::to_address(std::ranges::begin(range)), size);
102 else if constexpr (
requires { buffer.write(std::to_address(std::ranges::begin(range)), std::ranges::size(range)); } && std::ranges::sized_range<RANGE>)
104 const auto size = std::ranges::size(range);
106 buffer.write(std::to_address(std::ranges::begin(range)), size);
114 for (
auto&& value : std::forward<RANGE>(range))
125 template <
typename BUFFER,
typename CHAR_TYPE>
126 requires output_buffer<BUFFER, CHAR_TYPE>
129 return buffer_append_range(buffer, cstr, cstr + std::char_traits<CHAR_TYPE>::length(cstr));
133 template <
typename BUFFER,
typename CHAR_TYPE>
134 requires output_buffer<BUFFER, CHAR_TYPE>
137 return buffer_append_range(buffer, cstr, cstr + std::min(max_len, std::char_traits<CHAR_TYPE>::length(cstr)));
141 template <
typename BUFFER,
size_t N,
typename CHAR_TYPE>
142 requires output_buffer<BUFFER, CHAR_TYPE>
149 template <
typename BUFFER,
typename ELEMENT_TYPE = buffer_element_type<BUFFER>>
150 requires output_buffer<BUFFER, ELEMENT_TYPE>
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);
159 result +=
buffer_append(buffer, uint8_t(0x80 | (val & 0x7f)));
167 template <
typename BUFFER,
typename ELEMENT_TYPE = buffer_element_type<BUFFER>>
168 requires output_buffer<BUFFER, ELEMENT_TYPE>
174 result +=
buffer_append(buffer,
static_cast<ELEMENT_TYPE
>(cp));
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));
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));
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));
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>
210 template <
typename BUFFER,
typename POD>
211 requires std::is_trivially_copyable_v<POD> && bytelike<buffer_element_type<BUFFER>>
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)
227 auto text = consume_until(fmt, '{');
228 buffer_append_range(buffer, text);
231 std::ignore = consume(fmt, '{');
233 if (consume(fmt, '{'))
235 buffer_append_range(buffer, '{');
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())
246 auto num = string_ops::consume_until(fmt_clause, ':');
248 aid = string_ops::stoull(num);
249 fmt_clause_str += fmt_clause;
251 fmt_clause_str += '}';
252 callback(aid, std::string_view{ fmt_clause_str }, buffer);
261 enum class buffer_compression_error_type
269 struct buffer_compression_error
271 buffer_compression_error_type type{};
272 std::string description;
275 template <
typename T>
276 using buffer_compression_result = expected<T, buffer_compression_error>;
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;
294 template <
typename BUFFER,
bytelike_range RANGE,
typename COMPRESSOR>
295 buffer_compression_result<void> buffer_append_compressed(BUFFER& buffer, RANGE&& input_range, COMPRESSOR& comp)
298 return compressor_restart(comp)
299 .and_then([&] {
return compressor_compress_fragment(comp, input_range, buffer); })
300 .and_then([&] {
return compressor_finalize(comp, buffer); });
Checks if an element value is appendable to a buffer.
bool buffer_append(BUFFER &&buffer, T &&val)
Primary function to append a value (preferably the buffer element type) to the buffer.
size_t buffer_append_pod(BUFFER &buffer, POD const &pod)
Appends a POD value's internal object representation to a buffer.
bool buffer_reserve(BUFFER &buffer, size_t additional)
Reserves additional elements in the buffer, if possible.
size_t buffer_append_cstring(BUFFER &buffer, const CHAR_TYPE(&cstr)[N])
Appends characters in the cstr literal array to the buffer.
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...
typename decltype(detail::deduce_buffer_element_type< BUFFER >())::type buffer_element_type
Resolves to the destination element type of the buffer.
size_t buffer_append_range(BUFFER &buffer, RANGE &&range)
Appends elements in the range to the buffer.
size_t buffer_append_cstring_ptr(BUFFER &buffer, const CHAR_TYPE *cstr)
Appends characters in the cstr to the buffer.
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...
std::span< TO > as_bytelikes(std::span< FROM, N > elements) noexcept
Converts a span of trivial values to a span of bytelike s.
Primary namespace for everything in this library.