header_utils
Loading...
Searching...
No Matches
buffers.h
1
4
5#pragma once
6
7#include "bytes.h"
8
9namespace ghassanpl
10{
11 namespace detail
12 {
13 template <typename BUFFER>
14 consteval auto deduce_buffer_element_type() noexcept
15 {
16 if constexpr (requires { typename BUFFER::value_type; })
17 return std::type_identity<typename BUFFER::value_type>{};
18 else if constexpr (requires { typename BUFFER::char_type; })
19 return std::type_identity<typename BUFFER::char_type>{};
20 }
21 }
22
25
28
30 template <typename BUFFER>
31 using buffer_element_type = typename decltype(detail::deduce_buffer_element_type<BUFFER>())::type;
32
34 template <typename BUFFER, typename T>
36 {
37 if constexpr (requires { buffer.append(val); })
38 {
39 buffer.append(val);
40 return true;
41 }
42 else if constexpr (requires { buffer.push_back(val); })
43 {
44 buffer.push_back(val);
45 return true;
46 }
47 else if constexpr (requires { buffer.insert(buffer.end(), val); })
48 {
49 buffer.insert(buffer.end(), val);
50 return true;
51 }
52 else if constexpr (requires { buffer.put(val); })
53 {
54 buffer.put(val);
55 return true;
56 }
57 else
58 {
59 static_assert(!std::same_as<T, T>, "buffer cannot be appended with this value type - buffer_append might need to be specialized");
60 return false;
61 }
62 }
63
65 template <typename BUFFER, typename ELEMENT_VALUE>
68 };
69
71 template <typename BUFFER>
73 {
74 if constexpr (requires { buffer.reserve(std::ranges::size(buffer) + additional); })
75 {
76 buffer.reserve(std::ranges::size(buffer) + additional);
77 return true;
78 }
79 else
80 return false;
81 }
82
84 template <typename BUFFER, typename RANGE>
87 {
88 if constexpr (std::ranges::sized_range<RANGE>)
89 buffer_reserve(buffer, std::ranges::size(range));
90
91 /*
92 if constexpr (requires { buffer.append(val); })
93 {
94 buffer.append(val);
95 return true;
96 }
97 else if constexpr (requires { buffer.push_back(val); })
98 {
99 buffer.push_back(val);
100 return true;
101 }
102 else if constexpr (requires { buffer.insert(buffer.end(), val); })
103 {
104 buffer.insert(buffer.end(), val);
105 return true;
106 }
107 else
108 */
109 if constexpr (requires { buffer.append(std::to_address(std::ranges::begin(range)), std::ranges::size(range)); } && std::ranges::sized_range<RANGE>)
110 {
111 const auto size = std::ranges::size(range);
112 buffer.append(std::to_address(std::ranges::begin(range)), size);
113 return size;
114 }
115 else if constexpr (requires { buffer.write(std::to_address(std::ranges::begin(range)), std::ranges::size(range)); } && std::ranges::sized_range<RANGE>)
116 {
117 const auto size = std::ranges::size(range);
119 buffer.write(std::to_address(std::ranges::begin(range)), size);
122 return size;
123 }
124 else
125 {
126 size_t count = 0;
127 for (auto&& value : std::forward<RANGE>(range))
128 {
129 if (!buffer_append(buffer, value))
130 break;
131 ++count;
132 }
133 return count;
134 }
135 }
136
138 template <typename BUFFER, typename CHAR_TYPE>
141 {
142 return buffer_append_range(buffer, cstr, cstr + std::char_traits<CHAR_TYPE>::length(cstr));
143 }
144
146 template <typename BUFFER, typename CHAR_TYPE>
149 {
150 return buffer_append_range(buffer, cstr, cstr + std::min(max_len, std::char_traits<CHAR_TYPE>::length(cstr)));
151 }
152
154 template <typename BUFFER, size_t N, typename CHAR_TYPE>
157 {
158 return buffer_append_range(buffer, cstr, cstr + (N - 1));
159 }
160
162 template <typename BUFFER, typename ELEMENT_TYPE = buffer_element_type<BUFFER>>
164 size_t buffer_append_utf8(BUFFER& buffer, char32_t cp)
165 {
166 size_t result = 0;
167 if (cp < 0x80)
168 {
169 result += buffer_append(buffer, static_cast<ELEMENT_TYPE>(cp));
170 }
171 else if (cp < 0x800) {
172 result += buffer_append(buffer, static_cast<ELEMENT_TYPE>((cp >> 6) | 0xc0));
173 result += buffer_append(buffer, static_cast<ELEMENT_TYPE>((cp & 0x3f) | 0x80));
174 }
175 else if (cp < 0x10000) {
176 result += buffer_append(buffer, static_cast<ELEMENT_TYPE>((cp >> 12) | 0xe0));
177 result += buffer_append(buffer, static_cast<ELEMENT_TYPE>(((cp >> 6) & 0x3f) | 0x80));
178 result += buffer_append(buffer, static_cast<ELEMENT_TYPE>((cp & 0x3f) | 0x80));
179 }
180 else {
181 result += buffer_append(buffer, static_cast<ELEMENT_TYPE>((cp >> 18) | 0xf0));
182 result += buffer_append(buffer, static_cast<ELEMENT_TYPE>(((cp >> 12) & 0x3f) | 0x80));
183 result += buffer_append(buffer, static_cast<ELEMENT_TYPE>(((cp >> 6) & 0x3f) | 0x80));
184 result += buffer_append(buffer, static_cast<ELEMENT_TYPE>((cp & 0x3f) | 0x80));
185 }
186 return result;
187 }
188
191 template <typename BUFFER, typename STRING_TYPE, typename ELEMENT_TYPE = buffer_element_type<BUFFER>>
192 requires output_buffer<BUFFER, ELEMENT_TYPE> && std::ranges::range<STRING_TYPE> && std::same_as<std::ranges::range_value_t<STRING_TYPE>, char32_t>
194 {
195 size_t count = 0;
196 for (auto cp : str)
197 count += buffer_append_utf8(buffer, cp);
198 return count;
199 }
200
204 template <typename BUFFER, typename POD>
205 requires std::is_trivially_copyable_v<POD> && bytelike<buffer_element_type<BUFFER>>
207 {
209 }
210
212 template <typename BUFFER, typename CALLBACK>
213 requires std::invocable<CALLBACK, size_t, std::string_view, BUFFER&>
215 {
217 size_t aid = 0;
218 while (!fmt.empty())
219 {
220 auto text = consume_until(fmt, '{');
222 if (fmt.empty())
223 continue;
224 std::ignore = consume(fmt, '{');
225
226 if (consume(fmt, '{'))
227 {
229 continue;
230 }
231 else
232 {
233 std::string fmt_clause_str = "{";
236 throw std::format_error("missing '}' in format string");
237 if (!fmt_clause.empty())
238 {
240 if (!num.empty())
241 aid = string_ops::stoull(num);
243 }
244 fmt_clause_str += '}';
245 callback(aid, std::string_view{ fmt_clause_str }, buffer);
246 ++aid;
247 }
248 }
249 }
250
252}
Checks if an element value is appendable to a buffer.
Definition buffers.h:66
constexpr auto bit_count
Equal to the number of bits in the type.
Definition bits.h:33
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:156
typename decltype(detail::deduce_buffer_element_type< BUFFER >())::type buffer_element_type
Definition buffers.h:31
void callback_format_to(BUFFER &buffer, std::string_view fmt, CALLBACK &&callback)
TODO: Make this work - currently needs string_ops
Definition buffers.h:214
bool buffer_append(BUFFER &&buffer, T &&val)
Primary function to append a value (preferably the buffer element type) to the buffer.
Definition buffers.h:35
size_t buffer_append_pod(BUFFER &buffer, POD const &pod)
Appends a POD values internal object representation to a buffer.
Definition buffers.h:206
size_t buffer_append_cstring_ptr(BUFFER &buffer, const CHAR_TYPE *cstr)
Appends characters in the cstr to the buffer
Definition buffers.h:140
bool buffer_reserve(BUFFER &buffer, size_t additional)
Reserves additional elements in the buffer, if possible.
Definition buffers.h:72
size_t buffer_append_range(BUFFER &buffer, RANGE &&range)
Appends elements in the range to the buffer
Definition buffers.h:86
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:164
std::string_view consume_until(std::string_view &str, FUNC &&pred)
Consumes characters from the beginning of str until one matches pred(str[0]), exclusive.
Definition string_ops.h:788
std::string_view consume_until_delim(std::string_view &str, char c)
Consumes characters from the beginning of str until one is equal to c, inclusive.
Definition string_ops.h:844
bool consume_at_end(std::string_view &str, char val)
Consumes the last character from str if it matches val.
Definition string_ops.h:727
The below code is based on Sun's libm library code, which is licensed under the following license:
Primary namespace for everything in this library.
Definition align+rec2.h:10
std::span< TO > as_bytelikes(std::span< FROM, N > bytes) noexcept
Converts a span of trivial values to a span of bytelike s.
Definition bytes.h:27