/src/glaze/include/glaze/util/dump.hpp
Line | Count | Source |
1 | | // Glaze Library |
2 | | // For the license information refer to glaze.hpp |
3 | | |
4 | | #pragma once |
5 | | |
6 | | #include <bit> |
7 | | #include <cstddef> |
8 | | #include <cstring> |
9 | | #include <span> |
10 | | #include <string_view> |
11 | | |
12 | | #include "glaze/concepts/container_concepts.hpp" |
13 | | #include "glaze/core/opts.hpp" |
14 | | #include "glaze/util/convert.hpp" |
15 | | |
16 | | namespace glz |
17 | | { |
18 | | template <class T, class V = std::remove_cvref_t<T>> |
19 | | concept byte_sized = sizeof(T) == 1 && (std::same_as<V, char> || std::same_as<V, std::byte>); |
20 | | |
21 | | template <uint32_t N, class B> |
22 | | GLZ_ALWAYS_INLINE void maybe_pad(B& b, size_t ix) noexcept(not vector_like<B>) |
23 | | { |
24 | | if constexpr (vector_like<B>) { |
25 | | if (const auto k = ix + N; k > b.size()) [[unlikely]] { |
26 | | b.resize(2 * k); |
27 | | } |
28 | | } |
29 | | } |
30 | | |
31 | | template <class B> |
32 | | GLZ_ALWAYS_INLINE void maybe_pad(const size_t n, B& b, size_t ix) noexcept(not vector_like<B>) |
33 | | { |
34 | | if constexpr (vector_like<B>) { |
35 | | if (const auto k = ix + n; k > b.size()) [[unlikely]] { |
36 | | b.resize(2 * k); |
37 | | } |
38 | | } |
39 | | } |
40 | | |
41 | | template <auto c> |
42 | | GLZ_ALWAYS_INLINE void assign_maybe_cast(auto& b, size_t& ix) noexcept |
43 | | { |
44 | | using V = std::decay_t<decltype(b[0])>; |
45 | | using C = std::decay_t<decltype(c)>; |
46 | | if constexpr (std::same_as<V, C>) { |
47 | | b[ix] = c; |
48 | | } |
49 | | else { |
50 | | b[ix] = static_cast<V>(c); |
51 | | } |
52 | | } |
53 | | |
54 | | GLZ_ALWAYS_INLINE void assign_maybe_cast(const byte_sized auto c, auto& b, size_t& ix) noexcept |
55 | 0 | { |
56 | 0 | using V = std::decay_t<decltype(b[0])>; |
57 | 0 | using C = std::decay_t<decltype(c)>; |
58 | 0 | if constexpr (std::same_as<V, C>) { |
59 | 0 | b[ix] = c; |
60 | 0 | } |
61 | 0 | else { |
62 | 0 | b[ix] = static_cast<V>(c); |
63 | 0 | } |
64 | 0 | } |
65 | | |
66 | | // Low-level buffer write primitives (dump functions) |
67 | | // ================================================ |
68 | | // These functions write directly to the buffer WITHOUT bounds checking for bounded buffers. |
69 | | // |
70 | | // Contract: |
71 | | // - For resizable buffers (std::string, std::vector): Auto-resizes when Checked=true (default) |
72 | | // - For bounded buffers (std::array, std::span): Caller MUST call ensure_space() first |
73 | | // - For raw pointers: Caller assumes responsibility for sufficient space |
74 | | // |
75 | | // The Checked template parameter ONLY enables auto-resize for resizable buffers. |
76 | | // It does NOT enable bounds checking for bounded buffers - that would require ctx for error reporting |
77 | | // and would duplicate the ensure_space() logic. The padding model (ensure_space checks for |
78 | | // ix + n + write_padding_bytes) guarantees sufficient space for subsequent dump calls. |
79 | | |
80 | | template <bool Checked = true, class B> |
81 | | GLZ_ALWAYS_INLINE void dump(const byte_sized auto c, B& b, size_t& ix) noexcept(not vector_like<B>) |
82 | 0 | { |
83 | 0 | if constexpr (Checked && vector_like<B>) { |
84 | 0 | if (ix == b.size()) [[unlikely]] { |
85 | 0 | b.resize(b.size() == 0 ? 128 : b.size() * 2); |
86 | 0 | } |
87 | 0 | } |
88 | 0 | assign_maybe_cast(c, b, ix); |
89 | 0 | ++ix; |
90 | 0 | } |
91 | | |
92 | | template <auto c, bool Checked = true, class B> |
93 | | GLZ_ALWAYS_INLINE void dump(B& b, size_t& ix) noexcept(not vector_like<B>) |
94 | | { |
95 | | if constexpr (Checked && vector_like<B>) { |
96 | | if (ix == b.size()) [[unlikely]] { |
97 | | b.resize(b.size() == 0 ? 128 : b.size() * 2); |
98 | | } |
99 | | } |
100 | | assign_maybe_cast<c>(b, ix); |
101 | | ++ix; |
102 | | } |
103 | | |
104 | | template <string_literal str, bool Checked = true, class B> |
105 | | GLZ_ALWAYS_INLINE void dump(B& b, size_t& ix) noexcept(not vector_like<B>) |
106 | | { |
107 | | static constexpr auto s = str.sv(); |
108 | | static constexpr auto n = s.size(); |
109 | | |
110 | | if constexpr (vector_like<B>) { |
111 | | if constexpr (Checked) { |
112 | | const auto k = ix + n; |
113 | | if (k > b.size()) [[unlikely]] { |
114 | | b.resize(2 * k); |
115 | | } |
116 | | } |
117 | | } |
118 | | std::memcpy(&b[ix], s.data(), n); |
119 | | ix += n; |
120 | | } |
121 | | |
122 | | template <bool Checked = true, class B> |
123 | | GLZ_ALWAYS_INLINE void dump(const sv str, B& b, size_t& ix) noexcept(not vector_like<B>) |
124 | 0 | { |
125 | 0 | const auto n = str.size(); |
126 | 0 | if constexpr (vector_like<B>) { |
127 | 0 | if constexpr (Checked) { |
128 | 0 | const auto k = ix + n; |
129 | 0 | if (ix + n > b.size()) [[unlikely]] { |
130 | 0 | b.resize(2 * k); |
131 | 0 | } |
132 | 0 | } |
133 | 0 | } |
134 | 0 | std::memcpy(&b[ix], str.data(), n); |
135 | 0 | ix += n; |
136 | 0 | } |
137 | | |
138 | | template <auto c, class B> |
139 | | [[deprecated("use dumpn(c, n, b, ix) instead of dumpn<c>(n, b, ix) to reduce template instantiations")]] |
140 | | GLZ_ALWAYS_INLINE void dumpn(size_t n, B& b, size_t& ix) noexcept(not vector_like<B>) |
141 | | { |
142 | | if constexpr (vector_like<B>) { |
143 | | const auto k = ix + n; |
144 | | if (k > b.size()) [[unlikely]] { |
145 | | b.resize(2 * k); |
146 | | } |
147 | | } |
148 | | std::memset(&b[ix], c, n); |
149 | | ix += n; |
150 | | } |
151 | | |
152 | | template <class B> |
153 | | GLZ_ALWAYS_INLINE void dumpn(const byte_sized auto c, size_t n, B& b, size_t& ix) noexcept(not vector_like<B>) |
154 | 0 | { |
155 | 0 | if constexpr (vector_like<B>) { |
156 | 0 | const auto k = ix + n; |
157 | 0 | if (k > b.size()) [[unlikely]] { |
158 | 0 | b.resize(2 * k); |
159 | 0 | } |
160 | 0 | } |
161 | 0 | std::memset(&b[ix], c, n); |
162 | 0 | ix += n; |
163 | 0 | } |
164 | | |
165 | | template <auto c, class B> |
166 | | [[deprecated( |
167 | | "use dumpn_unchecked(c, n, b, ix) instead of dumpn_unchecked<c>(n, b, ix) to reduce template instantiations")]] |
168 | | GLZ_ALWAYS_INLINE void dumpn_unchecked(size_t n, B& b, size_t& ix) noexcept |
169 | | { |
170 | | std::memset(&b[ix], c, n); |
171 | | ix += n; |
172 | | } |
173 | | |
174 | | template <class B> |
175 | | GLZ_ALWAYS_INLINE void dumpn_unchecked(const byte_sized auto c, size_t n, B& b, size_t& ix) noexcept |
176 | | { |
177 | | std::memset(&b[ix], c, n); |
178 | | ix += n; |
179 | | } |
180 | | |
181 | | template <char IndentChar, class B> |
182 | | [[deprecated( |
183 | | "use dump_newline_indent(c, n, b, ix) instead of dump_newline_indent<c>(n, b, ix) to reduce template " |
184 | | "instantiations")]] |
185 | | GLZ_ALWAYS_INLINE void dump_newline_indent(size_t n, B& b, size_t& ix) noexcept(not vector_like<B>) |
186 | | { |
187 | | if constexpr (vector_like<B>) { |
188 | | if (const auto k = ix + n + write_padding_bytes; k > b.size()) [[unlikely]] { |
189 | | b.resize(2 * k); |
190 | | } |
191 | | } |
192 | | |
193 | | assign_maybe_cast<'\n'>(b, ix); |
194 | | ++ix; |
195 | | std::memset(&b[ix], IndentChar, n); |
196 | | ix += n; |
197 | | } |
198 | | |
199 | | template <class B> |
200 | | GLZ_ALWAYS_INLINE void dump_newline_indent(const byte_sized auto c, size_t n, B& b, |
201 | | size_t& ix) noexcept(not vector_like<B>) |
202 | | { |
203 | | if constexpr (vector_like<B>) { |
204 | | if (const auto k = ix + n + write_padding_bytes; k > b.size()) [[unlikely]] { |
205 | | b.resize(2 * k); |
206 | | } |
207 | | } |
208 | | |
209 | | assign_maybe_cast('\n', b, ix); |
210 | | ++ix; |
211 | | std::memset(&b[ix], c, n); |
212 | | ix += n; |
213 | | } |
214 | | |
215 | | template <const sv& str, bool Checked = true, class B> |
216 | | GLZ_ALWAYS_INLINE void dump(B& b, size_t& ix) noexcept(not vector_like<B> && not Checked) |
217 | | { |
218 | | static constexpr auto s = str; |
219 | | static constexpr auto n = s.size(); |
220 | | |
221 | | if constexpr (vector_like<B>) { |
222 | | if constexpr (Checked) { |
223 | | const auto k = ix + n; |
224 | | if (k > b.size()) [[unlikely]] { |
225 | | b.resize(2 * k); |
226 | | } |
227 | | } |
228 | | } |
229 | | std::memcpy(&b[ix], s.data(), n); |
230 | | ix += n; |
231 | | } |
232 | | |
233 | | template <bool Checked = true, class B> |
234 | | GLZ_ALWAYS_INLINE void dump_not_empty(const sv str, B& b, size_t& ix) noexcept(not vector_like<B> && not Checked) |
235 | 0 | { |
236 | 0 | const auto n = str.size(); |
237 | 0 | if constexpr (vector_like<B>) { |
238 | 0 | if constexpr (Checked) { |
239 | 0 | const auto k = ix + n; |
240 | 0 | if (k > b.size()) [[unlikely]] { |
241 | 0 | b.resize(2 * k); |
242 | 0 | } |
243 | 0 | } |
244 | 0 | } |
245 | 0 | std::memcpy(&b[ix], str.data(), n); |
246 | 0 | ix += n; |
247 | 0 | } |
248 | | |
249 | | template <bool Checked = true, class B> |
250 | | GLZ_ALWAYS_INLINE void dump_maybe_empty(const sv str, B& b, size_t& ix) noexcept(not vector_like<B> && not Checked) |
251 | 0 | { |
252 | 0 | const auto n = str.size(); |
253 | 0 | if (n) { |
254 | 0 | if constexpr (vector_like<B>) { |
255 | 0 | if constexpr (Checked) { |
256 | 0 | const auto k = ix + n; |
257 | 0 | if (k > b.size()) [[unlikely]] { |
258 | 0 | b.resize(2 * k); |
259 | 0 | } |
260 | 0 | } |
261 | 0 | } |
262 | 0 | std::memcpy(&b[ix], str.data(), n); |
263 | 0 | ix += n; |
264 | 0 | } |
265 | 0 | } |
266 | | |
267 | | template <class B> |
268 | | GLZ_ALWAYS_INLINE void dump(const vector_like auto& bytes, B& b, size_t& ix) noexcept(not vector_like<B>) |
269 | | { |
270 | | const auto n = bytes.size(); |
271 | | if constexpr (vector_like<B>) { |
272 | | const auto k = ix + n; |
273 | | if (k > b.size()) [[unlikely]] { |
274 | | b.resize(2 * k); |
275 | | } |
276 | | } |
277 | | std::memcpy(&b[ix], bytes.data(), n); |
278 | | ix += n; |
279 | | } |
280 | | |
281 | | template <size_t N, class B> |
282 | | GLZ_ALWAYS_INLINE void dump(const std::array<uint8_t, N>& bytes, B& b, size_t& ix) noexcept(not vector_like<B>) |
283 | | { |
284 | | if constexpr (vector_like<B>) { |
285 | | const auto k = ix + N; |
286 | | if (k > b.size()) [[unlikely]] { |
287 | | b.resize(2 * k); |
288 | | } |
289 | | } |
290 | | std::memcpy(&b[ix], bytes.data(), N); |
291 | | ix += N; |
292 | | } |
293 | | } |