Coverage Report

Created: 2026-08-13 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}