4#ifndef SIMDJSON_GENERIC_STRING_BUILDER_INL_H
6#ifndef SIMDJSON_CONDITIONAL_INCLUDE
7#define SIMDJSON_GENERIC_STRING_BUILDER_INL_H
8#include "simdjson/generic/builder/json_string_builder.h"
17#if defined(__SSE2__) || defined(__x86_64__) || defined(__x86_64) || \
18 (defined(_M_AMD64) || defined(_M_X64) || \
19 (defined(_M_IX86_FP) && _M_IX86_FP == 2))
20#ifndef SIMDJSON_EXPERIMENTAL_HAS_SSE2
21#define SIMDJSON_EXPERIMENTAL_HAS_SSE2 1
25#if defined(__aarch64__) || defined(_M_ARM64)
26#ifndef SIMDJSON_EXPERIMENTAL_HAS_NEON
27#define SIMDJSON_EXPERIMENTAL_HAS_NEON 1
30#if defined(__loongarch_sx)
31#ifndef SIMDJSON_EXPERIMENTAL_HAS_LSX
32#define SIMDJSON_EXPERIMENTAL_HAS_LSX 1
35#if defined(__riscv_v_intrinsic) && __riscv_v_intrinsic >= 11000 && \
36 defined(__riscv_vector)
37#ifndef SIMDJSON_EXPERIMENTAL_HAS_RVV
38#define SIMDJSON_EXPERIMENTAL_HAS_RVV 1
41#if (defined(__PPC64__) || defined(_M_PPC64)) && defined(__ALTIVEC__)
42#ifndef SIMDJSON_EXPERIMENTAL_HAS_PPC64
43#define SIMDJSON_EXPERIMENTAL_HAS_PPC64 1
46#if SIMDJSON_EXPERIMENTAL_HAS_NEON
52#if SIMDJSON_EXPERIMENTAL_HAS_SSE2
58#if SIMDJSON_EXPERIMENTAL_HAS_LSX
61#if SIMDJSON_EXPERIMENTAL_HAS_RVV
62#include <riscv_vector.h>
64#if SIMDJSON_EXPERIMENTAL_HAS_PPC64
76namespace SIMDJSON_IMPLEMENTATION {
79static SIMDJSON_CONSTEXPR_LAMBDA std::array<uint8_t, 256>
80 json_quotable_character = {
81 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
82 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
83 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
84 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
85 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
86 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
87 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
88 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
89 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
90 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
91 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
110SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline
bool
111simple_needs_escaping(std::string_view v) {
114 if (json_quotable_character[
static_cast<uint8_t
>(c)]) {
121#if SIMDJSON_EXPERIMENTAL_HAS_NEON
122simdjson_inline
bool fast_needs_escaping(std::string_view view) {
123 if (view.size() < 16) {
124 return simple_needs_escaping(view);
127 uint8x16_t running = vdupq_n_u8(0);
128 uint8x16_t v34 = vdupq_n_u8(34);
129 uint8x16_t v92 = vdupq_n_u8(92);
131 for (; i + 15 < view.size(); i += 16) {
132 uint8x16_t word = vld1q_u8((
const uint8_t *)view.data() + i);
133 running = vorrq_u8(running, vceqq_u8(word, v34));
134 running = vorrq_u8(running, vceqq_u8(word, v92));
135 running = vorrq_u8(running, vcltq_u8(word, vdupq_n_u8(32)));
137 if (i < view.size()) {
139 vld1q_u8((
const uint8_t *)view.data() + view.length() - 16);
140 running = vorrq_u8(running, vceqq_u8(word, v34));
141 running = vorrq_u8(running, vceqq_u8(word, v92));
142 running = vorrq_u8(running, vcltq_u8(word, vdupq_n_u8(32)));
144 return vmaxvq_u32(vreinterpretq_u32_u8(running)) != 0;
146#elif SIMDJSON_EXPERIMENTAL_HAS_SSE2
147simdjson_inline
bool fast_needs_escaping(std::string_view view) {
148 if (view.size() < 16) {
149 return simple_needs_escaping(view);
152 __m128i running = _mm_setzero_si128();
153 for (; i + 15 < view.size(); i += 16) {
156 _mm_loadu_si128(
reinterpret_cast<const __m128i *
>(view.data() + i));
157 running = _mm_or_si128(running, _mm_cmpeq_epi8(word, _mm_set1_epi8(34)));
158 running = _mm_or_si128(running, _mm_cmpeq_epi8(word, _mm_set1_epi8(92)));
159 running = _mm_or_si128(
160 running, _mm_cmpeq_epi8(_mm_subs_epu8(word, _mm_set1_epi8(31)),
161 _mm_setzero_si128()));
163 if (i < view.size()) {
164 __m128i word = _mm_loadu_si128(
165 reinterpret_cast<const __m128i *
>(view.data() + view.length() - 16));
166 running = _mm_or_si128(running, _mm_cmpeq_epi8(word, _mm_set1_epi8(34)));
167 running = _mm_or_si128(running, _mm_cmpeq_epi8(word, _mm_set1_epi8(92)));
168 running = _mm_or_si128(
169 running, _mm_cmpeq_epi8(_mm_subs_epu8(word, _mm_set1_epi8(31)),
170 _mm_setzero_si128()));
172 return _mm_movemask_epi8(running) != 0;
174#elif SIMDJSON_EXPERIMENTAL_HAS_PPC64
175simdjson_inline
bool fast_needs_escaping(std::string_view view) {
176 if (view.size() < 16) {
177 return simple_needs_escaping(view);
180 __vector
unsigned char running = vec_splats((
unsigned char)0);
181 __vector
unsigned char v34 = vec_splats((
unsigned char)34);
182 __vector
unsigned char v92 = vec_splats((
unsigned char)92);
183 __vector
unsigned char v32 = vec_splats((
unsigned char)32);
185 for (; i + 15 < view.size(); i += 16) {
186 __vector
unsigned char word =
187 vec_vsx_ld(0,
reinterpret_cast<const unsigned char *
>(view.data() + i));
188 running = vec_or(running, (__vector
unsigned char)vec_cmpeq(word, v34));
189 running = vec_or(running, (__vector
unsigned char)vec_cmpeq(word, v92));
190 running = vec_or(running,
191 (__vector
unsigned char)vec_cmplt(word, v32));
193 if (i < view.size()) {
194 __vector
unsigned char word = vec_vsx_ld(
195 0,
reinterpret_cast<const unsigned char *
>(view.data() + view.length() - 16));
196 running = vec_or(running, (__vector
unsigned char)vec_cmpeq(word, v34));
197 running = vec_or(running, (__vector
unsigned char)vec_cmpeq(word, v92));
198 running = vec_or(running,
199 (__vector
unsigned char)vec_cmplt(word, v32));
201 return !vec_all_eq(running, vec_splats((
unsigned char)0));
204simdjson_inline
bool fast_needs_escaping(std::string_view view) {
205 return simple_needs_escaping(view);
210SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline
size_t
211find_next_json_quotable_character_scalar(
const std::string_view view,
212 size_t location)
noexcept {
213 for (
auto pos = view.begin() + location; pos != view.end(); ++pos) {
214 if (json_quotable_character[
static_cast<uint8_t
>(*pos)]) {
215 return pos - view.begin();
218 return size_t(view.size());
224#if SIMDJSON_EXPERIMENTAL_HAS_NEON
225simdjson_inline
size_t
226find_next_json_quotable_character(
const std::string_view view,
227 size_t location)
noexcept {
228 const size_t len = view.size();
230 reinterpret_cast<const uint8_t *
>(view.data()) + location;
231 size_t remaining = len - location;
234 uint8x16_t v34 = vdupq_n_u8(34);
235 uint8x16_t v92 = vdupq_n_u8(92);
236 uint8x16_t v32 = vdupq_n_u8(32);
238 while (remaining >= 16) {
239 uint8x16_t word = vld1q_u8(ptr);
242 uint8x16_t needs_escape = vceqq_u8(word, v34);
243 needs_escape = vorrq_u8(needs_escape, vceqq_u8(word, v92));
244 needs_escape = vorrq_u8(needs_escape, vcltq_u8(word, v32));
246 const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(needs_escape), 4);
247 const uint64_t mask = vget_lane_u64(vreinterpret_u64_u8(res), 0);
249 size_t offset = ptr -
reinterpret_cast<const uint8_t *
>(view.data());
250 auto trailing_zero = trailing_zeroes(mask);
251 return offset + (trailing_zero >> 2);
258 size_t current = len - remaining;
259 return find_next_json_quotable_character_scalar(view, current);
261#elif SIMDJSON_EXPERIMENTAL_HAS_SSE2
262simdjson_inline
size_t
263find_next_json_quotable_character(
const std::string_view view,
264 size_t location)
noexcept {
265 const size_t len = view.size();
267 reinterpret_cast<const uint8_t *
>(view.data()) + location;
268 size_t remaining = len - location;
271 __m128i v34 = _mm_set1_epi8(34);
272 __m128i v92 = _mm_set1_epi8(92);
273 __m128i v31 = _mm_set1_epi8(31);
275 while (remaining >= 16) {
276 __m128i word = _mm_loadu_si128(
reinterpret_cast<const __m128i *
>(ptr));
279 __m128i needs_escape = _mm_cmpeq_epi8(word, v34);
280 needs_escape = _mm_or_si128(needs_escape, _mm_cmpeq_epi8(word, v92));
281 needs_escape = _mm_or_si128(
283 _mm_cmpeq_epi8(_mm_subs_epu8(word, v31), _mm_setzero_si128()));
285 int mask = _mm_movemask_epi8(needs_escape);
288 size_t offset = ptr -
reinterpret_cast<const uint8_t *
>(view.data());
289 return offset + trailing_zeroes(mask);
296 size_t current = len - remaining;
297 return find_next_json_quotable_character_scalar(view, current);
299#elif SIMDJSON_EXPERIMENTAL_HAS_LSX
300simdjson_inline
size_t
301find_next_json_quotable_character(
const std::string_view view,
302 size_t location)
noexcept {
303 const size_t len = view.size();
305 reinterpret_cast<const uint8_t *
>(view.data()) + location;
306 size_t remaining = len - location;
309 __m128i v34 = __lsx_vreplgr2vr_b(34);
310 __m128i v92 = __lsx_vreplgr2vr_b(92);
311 __m128i v32 = __lsx_vreplgr2vr_b(32);
313 while (remaining >= 16){
314 __m128i word = __lsx_vld(ptr, 0);
317 __m128i needs_escape = __lsx_vseq_b(word, v34);
318 needs_escape = __lsx_vor_v(needs_escape, __lsx_vseq_b(word, v92));
319 needs_escape = __lsx_vor_v(needs_escape, __lsx_vslt_bu(word, v32));
321 if (!__lsx_bz_v(needs_escape)){
324 uint64_t lo = __lsx_vpickve2gr_du(needs_escape,0);
325 uint64_t hi = __lsx_vpickve2gr_du(needs_escape,1);
326 size_t offset = ptr -
reinterpret_cast<const uint8_t *
>(view.data());
328 return offset + trailing_zeroes(lo) / 8;
330 return offset + 8 + trailing_zeroes(hi) / 8;
336 size_t current = len - remaining;
337 return find_next_json_quotable_character_scalar(view, current);
339#elif SIMDJSON_EXPERIMENTAL_HAS_RVV
340simdjson_inline
size_t
341find_next_json_quotable_character(
const std::string_view view,
342 size_t location)
noexcept {
343 const size_t len = view.size();
345 reinterpret_cast<const uint8_t *
>(view.data()) + location;
346 size_t remaining = len - location;
348 while (remaining > 0) {
349 size_t vl = __riscv_vsetvl_e8m1(remaining);
350 vuint8m1_t word = __riscv_vle8_v_u8m1(ptr, vl);
353 vbool8_t needs_escape = __riscv_vmseq(word, (uint8_t)34, vl);
354 needs_escape = __riscv_vmor(needs_escape,
355 __riscv_vmseq(word, (uint8_t)92, vl), vl);
356 needs_escape = __riscv_vmor(needs_escape,
357 __riscv_vmsltu(word, (uint8_t)32, vl), vl);
359 long first = __riscv_vfirst(needs_escape, vl);
361 size_t offset = ptr -
reinterpret_cast<const uint8_t *
>(view.data());
362 return offset + first;
370#elif SIMDJSON_EXPERIMENTAL_HAS_PPC64
371simdjson_inline
size_t
372find_next_json_quotable_character(
const std::string_view view,
373 size_t location)
noexcept {
374 const size_t len = view.size();
376 reinterpret_cast<const uint8_t *
>(view.data()) + location;
377 size_t remaining = len - location;
380 __vector
unsigned char v34 = vec_splats((
unsigned char)34);
381 __vector
unsigned char v92 = vec_splats((
unsigned char)92);
382 __vector
unsigned char v32 = vec_splats((
unsigned char)32);
385 const __vector
unsigned char perm_mask = {0x78, 0x70, 0x68, 0x60, 0x58, 0x50,
386 0x48, 0x40, 0x38, 0x30, 0x28, 0x20,
387 0x18, 0x10, 0x08, 0x00};
389 while (remaining >= 16) {
390 __vector
unsigned char word =
391 vec_vsx_ld(0,
reinterpret_cast<const unsigned char *
>(ptr));
394 __vector
unsigned char needs_escape =
395 (__vector
unsigned char)vec_cmpeq(word, v34);
396 needs_escape = vec_or(needs_escape,
397 (__vector
unsigned char)vec_cmpeq(word, v92));
398 needs_escape = vec_or(needs_escape,
399 (__vector
unsigned char)vec_cmplt(word, v32));
401 __vector
unsigned long long result =
402 (__vector
unsigned long long)vec_vbpermq(needs_escape, perm_mask);
403#ifdef __LITTLE_ENDIAN__
404 unsigned int mask =
static_cast<unsigned int>(result[1]);
406 unsigned int mask =
static_cast<unsigned int>(result[0]);
409 size_t offset = ptr -
reinterpret_cast<const uint8_t *
>(view.data());
410 return offset + __builtin_ctz(mask);
417 size_t current = len - remaining;
418 return find_next_json_quotable_character_scalar(view, current);
421SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline
size_t
422find_next_json_quotable_character(
const std::string_view view,
423 size_t location)
noexcept {
424 return find_next_json_quotable_character_scalar(view, location);
428SIMDJSON_CONSTEXPR_LAMBDA
static std::string_view control_chars[] = {
429 "\\u0000",
"\\u0001",
"\\u0002",
"\\u0003",
"\\u0004",
"\\u0005",
"\\u0006",
430 "\\u0007",
"\\b",
"\\t",
"\\n",
"\\u000b",
"\\f",
"\\r",
431 "\\u000e",
"\\u000f",
"\\u0010",
"\\u0011",
"\\u0012",
"\\u0013",
"\\u0014",
432 "\\u0015",
"\\u0016",
"\\u0017",
"\\u0018",
"\\u0019",
"\\u001a",
"\\u001b",
433 "\\u001c",
"\\u001d",
"\\u001e",
"\\u001f"};
440SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline
void escape_json_char(
char c,
char *&out) {
442 memcpy(out,
"\\\"", 2);
444 }
else if (c ==
'\\') {
445 memcpy(out,
"\\\\", 2);
448 std::string_view v = control_chars[uint8_t(c)];
449 memcpy(out, v.data(), v.size());
456inline size_t write_string_escaped(
const std::string_view input,
char *out) {
457 size_t mysize = input.size();
460 size_t location = find_next_json_quotable_character(input, 0);
461 if (location == mysize) {
463 memcpy(out, input.data(), input.size());
467 const char *
const initout = out;
468 memcpy(out, input.data(), location);
470 escape_json_char(input[location], out);
472 while (location < mysize) {
473 size_t newlocation = find_next_json_quotable_character(input, location);
474 memcpy(out, input.data() + location, newlocation - location);
475 out += newlocation - location;
476 location = newlocation;
477 if (location == mysize) {
480 escape_json_char(input[location], out);
483 return out - initout;
486simdjson_inline string_builder::string_builder(
size_t initial_capacity)
487 : buffer(new(std::nothrow) char[initial_capacity]), position(0),
488 capacity(buffer.get() != nullptr ? initial_capacity : 0),
489 is_valid(buffer.get() != nullptr) {}
491simdjson_inline
bool string_builder::capacity_check(
size_t upcoming_bytes) {
495 if (simdjson_likely(upcoming_bytes <= capacity - position)) {
499 if (simdjson_unlikely(position + upcoming_bytes < position)) {
503 grow_buffer((std::max)(capacity * 2, position + upcoming_bytes));
508simdjson_inline
void string_builder::grow_buffer(
size_t desired_capacity) {
512 std::unique_ptr<char[]> new_buffer(
new (std::nothrow)
char[desired_capacity]);
513 if (new_buffer.get() ==
nullptr) {
517 std::memcpy(new_buffer.get(), buffer.get(), position);
518 buffer.swap(new_buffer);
519 capacity = desired_capacity;
522simdjson_inline
void string_builder::set_valid(
bool valid)
noexcept {
533simdjson_inline
size_t string_builder::size() const noexcept {
537simdjson_inline
void string_builder::append(
char c)
noexcept {
538 if (capacity_check(1)) {
539 buffer.get()[position++] = c;
543simdjson_inline
void string_builder::append_null() noexcept {
544 constexpr char null_literal[] =
"null";
545 constexpr size_t null_len =
sizeof(null_literal) - 1;
546 if (capacity_check(null_len)) {
547 std::memcpy(buffer.get() + position, null_literal, null_len);
548 position += null_len;
552simdjson_inline
void string_builder::clear() noexcept {
564template <
typename number_type,
typename =
typename std::enable_if<
565 std::is_unsigned<number_type>::value>::type>
566simdjson_really_inline
int int_log2(number_type x) {
567 return 63 - leading_zeroes(uint64_t(x) | 1);
570simdjson_really_inline
int fast_digit_count_32(uint32_t x) {
571 static uint64_t table[] = {
572 4294967296, 8589934582, 8589934582, 8589934582, 12884901788,
573 12884901788, 12884901788, 17179868184, 17179868184, 17179868184,
574 21474826480, 21474826480, 21474826480, 21474826480, 25769703776,
575 25769703776, 25769703776, 30063771072, 30063771072, 30063771072,
576 34349738368, 34349738368, 34349738368, 34349738368, 38554705664,
577 38554705664, 38554705664, 41949672960, 41949672960, 41949672960,
578 42949672960, 42949672960};
579 return uint32_t((x + table[int_log2(x)]) >> 32);
582simdjson_really_inline
int fast_digit_count_64(uint64_t x) {
583 static uint64_t table[] = {9,
599 99999999999999999ULL,
600 999999999999999999ULL,
601 9999999999999999999ULL};
602 int y = (19 * int_log2(x) >> 6);
607template <
typename number_type,
typename =
typename std::enable_if<
608 std::is_unsigned<number_type>::value>::type>
609simdjson_really_inline
size_t digit_count(number_type v)
noexcept {
610 static_assert(
sizeof(number_type) == 8 ||
sizeof(number_type) == 4 ||
611 sizeof(number_type) == 2 ||
sizeof(number_type) == 1,
612 "We only support 8-bit, 16-bit, 32-bit and 64-bit numbers");
613 SIMDJSON_IF_CONSTEXPR(
sizeof(number_type) <= 4) {
614 return fast_digit_count_32(
static_cast<uint32_t
>(v));
617 return fast_digit_count_64(
static_cast<uint64_t
>(v));
620static const char decimal_table[200] = {
621 0x30, 0x30, 0x30, 0x31, 0x30, 0x32, 0x30, 0x33, 0x30, 0x34, 0x30, 0x35,
622 0x30, 0x36, 0x30, 0x37, 0x30, 0x38, 0x30, 0x39, 0x31, 0x30, 0x31, 0x31,
623 0x31, 0x32, 0x31, 0x33, 0x31, 0x34, 0x31, 0x35, 0x31, 0x36, 0x31, 0x37,
624 0x31, 0x38, 0x31, 0x39, 0x32, 0x30, 0x32, 0x31, 0x32, 0x32, 0x32, 0x33,
625 0x32, 0x34, 0x32, 0x35, 0x32, 0x36, 0x32, 0x37, 0x32, 0x38, 0x32, 0x39,
626 0x33, 0x30, 0x33, 0x31, 0x33, 0x32, 0x33, 0x33, 0x33, 0x34, 0x33, 0x35,
627 0x33, 0x36, 0x33, 0x37, 0x33, 0x38, 0x33, 0x39, 0x34, 0x30, 0x34, 0x31,
628 0x34, 0x32, 0x34, 0x33, 0x34, 0x34, 0x34, 0x35, 0x34, 0x36, 0x34, 0x37,
629 0x34, 0x38, 0x34, 0x39, 0x35, 0x30, 0x35, 0x31, 0x35, 0x32, 0x35, 0x33,
630 0x35, 0x34, 0x35, 0x35, 0x35, 0x36, 0x35, 0x37, 0x35, 0x38, 0x35, 0x39,
631 0x36, 0x30, 0x36, 0x31, 0x36, 0x32, 0x36, 0x33, 0x36, 0x34, 0x36, 0x35,
632 0x36, 0x36, 0x36, 0x37, 0x36, 0x38, 0x36, 0x39, 0x37, 0x30, 0x37, 0x31,
633 0x37, 0x32, 0x37, 0x33, 0x37, 0x34, 0x37, 0x35, 0x37, 0x36, 0x37, 0x37,
634 0x37, 0x38, 0x37, 0x39, 0x38, 0x30, 0x38, 0x31, 0x38, 0x32, 0x38, 0x33,
635 0x38, 0x34, 0x38, 0x35, 0x38, 0x36, 0x38, 0x37, 0x38, 0x38, 0x38, 0x39,
636 0x39, 0x30, 0x39, 0x31, 0x39, 0x32, 0x39, 0x33, 0x39, 0x34, 0x39, 0x35,
637 0x39, 0x36, 0x39, 0x37, 0x39, 0x38, 0x39, 0x39,
641template <
typename number_type,
typename>
642simdjson_inline
void string_builder::append(number_type v)
noexcept {
643 static_assert(std::is_same<number_type, bool>::value ||
644 std::is_integral<number_type>::value ||
645 std::is_floating_point<number_type>::value,
646 "Unsupported number type");
648 SIMDJSON_IF_CONSTEXPR(std::is_same<number_type, bool>::value) {
650 constexpr char true_literal[] =
"true";
651 constexpr size_t true_len =
sizeof(true_literal) - 1;
652 if (capacity_check(true_len)) {
653 std::memcpy(buffer.get() + position, true_literal, true_len);
654 position += true_len;
657 constexpr char false_literal[] =
"false";
658 constexpr size_t false_len =
sizeof(false_literal) - 1;
659 if (capacity_check(false_len)) {
660 std::memcpy(buffer.get() + position, false_literal, false_len);
661 position += false_len;
665 else SIMDJSON_IF_CONSTEXPR(std::is_unsigned<number_type>::value) {
668 constexpr size_t max_number_size = 20;
669 if (capacity_check(max_number_size)) {
670 using unsigned_type =
typename std::make_unsigned<number_type>::type;
671 unsigned_type pv =
static_cast<unsigned_type
>(v);
672 size_t dc = internal::digit_count(pv);
673 char *write_pointer = buffer.get() + position + dc - 1;
676 while (pv >= 10000) {
677 unsigned_type q = pv / 10000;
678 unsigned_type r = pv % 10000;
679 unsigned_type r_hi = r / 100;
680 unsigned_type r_lo = r % 100;
682 memcpy(write_pointer - 1, &internal::decimal_table[r_lo * 2], 2);
683 memcpy(write_pointer - 3, &internal::decimal_table[r_hi * 2], 2);
690 memcpy(write_pointer - 1, &internal::decimal_table[(pv % 100) * 2], 2);
695 *write_pointer-- = char(
'0' + (pv % 10));
698 *write_pointer = char(
'0' + pv);
702 else SIMDJSON_IF_CONSTEXPR(std::is_integral<number_type>::value) {
704 constexpr size_t max_number_size = 20;
705 if (capacity_check(max_number_size)) {
706 using unsigned_type =
typename std::make_unsigned<number_type>::type;
707 bool negative = v < 0;
708 unsigned_type pv =
static_cast<unsigned_type
>(v);
712 size_t dc = internal::digit_count(pv);
714 buffer.get()[position] =
'-';
715 position += negative ? 1 : 0;
716 char *write_pointer = buffer.get() + position + dc - 1;
719 while (pv >= 10000) {
720 unsigned_type q = pv / 10000;
721 unsigned_type r = pv % 10000;
722 unsigned_type r_hi = r / 100;
723 unsigned_type r_lo = r % 100;
724 memcpy(write_pointer - 1, &internal::decimal_table[r_lo * 2], 2);
725 memcpy(write_pointer - 3, &internal::decimal_table[r_hi * 2], 2);
732 memcpy(write_pointer - 1, &internal::decimal_table[(pv % 100) * 2], 2);
737 *write_pointer-- = char(
'0' + (pv % 10));
740 *write_pointer = char(
'0' + pv);
744 else SIMDJSON_IF_CONSTEXPR(std::is_floating_point<number_type>::value) {
745 constexpr size_t max_number_size = 24;
746 if (capacity_check(max_number_size)) {
748 char *end = simdjson::internal::to_chars(buffer.get() + position,
nullptr,
750 position = end - buffer.get();
756string_builder::escape_and_append(std::string_view input)
noexcept {
758 if (capacity_check(6 * input.size())) {
759 position += write_string_escaped(input, buffer.get() + position);
764string_builder::escape_and_append_with_quotes(std::string_view input)
noexcept {
766 if (capacity_check(2 + 6 * input.size())) {
767 buffer.get()[position++] =
'"';
768 position += write_string_escaped(input, buffer.get() + position);
769 buffer.get()[position++] =
'"';
774string_builder::escape_and_append_with_quotes(
char input)
noexcept {
776 if (capacity_check(2 + 6 * 1)) {
777 buffer.get()[position++] =
'"';
778 std::string_view cinput(&input, 1);
779 position += write_string_escaped(cinput, buffer.get() + position);
780 buffer.get()[position++] =
'"';
785string_builder::escape_and_append_with_quotes(
const char *input)
noexcept {
786 std::string_view cinput(input);
787 escape_and_append_with_quotes(cinput);
789#if SIMDJSON_SUPPORTS_CONCEPTS
790template <constevalutil::fixed_
string key>
791simdjson_inline
void string_builder::escape_and_append_with_quotes() noexcept {
792 escape_and_append_with_quotes(constevalutil::string_constant<key>::value);
796simdjson_inline
void string_builder::append_raw(
const char *c)
noexcept {
797 size_t len = std::strlen(c);
802string_builder::append_raw(std::string_view input)
noexcept {
803 if (capacity_check(input.size())) {
804 std::memcpy(buffer.get() + position, input.data(), input.size());
805 position += input.size();
809simdjson_inline
void string_builder::append_raw(
const char *str,
810 size_t len)
noexcept {
811 if (capacity_check(len)) {
812 std::memcpy(buffer.get() + position, str, len);
816#if SIMDJSON_SUPPORTS_CONCEPTS
818template <concepts::optional_type T>
819 requires(!require_custom_serialization<T>)
820simdjson_inline
void string_builder::append(
const T &opt) {
829 requires(require_custom_serialization<T>)
830simdjson_inline
void string_builder::append(T &&val) {
831 serialize(*
this, std::forward<T>(val));
835 requires(std::is_convertible<T, std::string_view>::value ||
836 std::is_same<T, const char *>::value)
837simdjson_inline
void string_builder::append(
const T &value) {
838 escape_and_append_with_quotes(value);
842#if SIMDJSON_SUPPORTS_RANGES && SIMDJSON_SUPPORTS_CONCEPTS
844template <std::ranges::range R>
845 requires(!std::is_convertible<R, std::string_view>::value && !require_custom_serialization<R>)
846simdjson_inline
void string_builder::append(
const R &range)
noexcept {
847 auto it = std::ranges::begin(range);
848 auto end = std::ranges::end(range);
849 if constexpr (concepts::is_pair<std::ranges::range_value_t<R>>) {
857 append_key_value(it->first, it->second);
861 for (; it != end; ++it) {
863 append_key_value(it->first, it->second);
878 for (; it != end; ++it) {
888#if SIMDJSON_EXCEPTIONS
889simdjson_inline string_builder::operator std::string() const noexcept(false) {
890 return std::string(
operator std::string_view());
893simdjson_inline string_builder::operator std::string_view() const
894 noexcept(false) simdjson_lifetime_bound {
900string_builder::view() const noexcept {
904 return std::string_view(buffer.get(), position);
908 if (capacity_check(1)) {
909 buffer.
get()[position] =
'\0';
915simdjson_inline
bool string_builder::validate_unicode() const noexcept {
919simdjson_inline
void string_builder::start_object() noexcept {
920 if (capacity_check(1)) {
921 buffer.get()[position++] =
'{';
925simdjson_inline
void string_builder::end_object() noexcept {
926 if (capacity_check(1)) {
927 buffer.get()[position++] =
'}';
931simdjson_inline
void string_builder::start_array() noexcept {
932 if (capacity_check(1)) {
933 buffer.get()[position++] =
'[';
937simdjson_inline
void string_builder::end_array() noexcept {
938 if (capacity_check(1)) {
939 buffer.get()[position++] =
']';
943simdjson_inline
void string_builder::append_comma() noexcept {
944 if (capacity_check(1)) {
945 buffer.get()[position++] =
',';
949simdjson_inline
void string_builder::append_colon() noexcept {
950 if (capacity_check(1)) {
951 buffer.get()[position++] =
':';
955template <
typename key_type,
typename value_type>
957string_builder::append_key_value(key_type key, value_type value)
noexcept {
958 static_assert(std::is_same<key_type, const char *>::value ||
959 std::is_convertible<key_type, std::string_view>::value,
960 "Unsupported key type");
961 escape_and_append_with_quotes(key);
963 SIMDJSON_IF_CONSTEXPR(std::is_same<value_type, std::nullptr_t>::value) {
966 else SIMDJSON_IF_CONSTEXPR(std::is_same<value_type, char>::value) {
967 escape_and_append_with_quotes(value);
969 else SIMDJSON_IF_CONSTEXPR(
970 std::is_convertible<value_type, std::string_view>::value) {
971 escape_and_append_with_quotes(value);
973 else SIMDJSON_IF_CONSTEXPR(std::is_same<value_type, const char *>::value) {
974 escape_and_append_with_quotes(value);
981#if SIMDJSON_SUPPORTS_CONCEPTS
982template <constevalutil::fixed_
string key,
typename value_type>
984string_builder::append_key_value(value_type value)
noexcept {
985 escape_and_append_with_quotes<key>();
987 SIMDJSON_IF_CONSTEXPR(std::is_same<value_type, std::nullptr_t>::value) {
990 else SIMDJSON_IF_CONSTEXPR(std::is_same<value_type, char>::value) {
991 escape_and_append_with_quotes(value);
993 else SIMDJSON_IF_CONSTEXPR(
994 std::is_convertible<value_type, std::string_view>::value) {
995 escape_and_append_with_quotes(value);
997 else SIMDJSON_IF_CONSTEXPR(std::is_same<value_type, const char *>::value) {
998 escape_and_append_with_quotes(value);
The top level simdjson namespace, containing everything the library provides.
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) noexcept
Validate the UTF-8 string.
@ OUT_OF_CAPACITY
The capacity was exceeded, we cannot allocate enough memory.
The result of a simdjson operation that could fail.
simdjson_warn_unused simdjson_inline error_code get(T &value) &&noexcept
Move the value to the provided variable.