6#ifndef SIMDJSON_GENERIC_STRING_BUILDER_INL_H
8#ifndef SIMDJSON_CONDITIONAL_INCLUDE
9#define SIMDJSON_GENERIC_STRING_BUILDER_INL_H
10#include "simdjson/generic/builder/json_string_builder.h"
19#if defined(__SSE2__) || defined(__x86_64__) || defined(__x86_64) || \
20 (defined(_M_AMD64) || defined(_M_X64) || \
21 (defined(_M_IX86_FP) && _M_IX86_FP == 2))
22#ifndef SIMDJSON_EXPERIMENTAL_HAS_SSE2
23#define SIMDJSON_EXPERIMENTAL_HAS_SSE2 1
27#if defined(__aarch64__) || defined(_M_ARM64)
28#ifndef SIMDJSON_EXPERIMENTAL_HAS_NEON
29#define SIMDJSON_EXPERIMENTAL_HAS_NEON 1
32#if defined(__loongarch_sx)
33#ifndef SIMDJSON_EXPERIMENTAL_HAS_LSX
34#define SIMDJSON_EXPERIMENTAL_HAS_LSX 1
37#if defined(__loongarch_asx)
38#ifndef SIMDJSON_EXPERIMENTAL_HAS_LASX
39#define SIMDJSON_EXPERIMENTAL_HAS_LASX 1
42#if defined(__riscv_v_intrinsic) && __riscv_v_intrinsic >= 11000 && \
43 defined(__riscv_vector)
44#ifndef SIMDJSON_EXPERIMENTAL_HAS_RVV
45#define SIMDJSON_EXPERIMENTAL_HAS_RVV 1
48#if (defined(__PPC64__) || defined(_M_PPC64)) && defined(__ALTIVEC__) && defined(__POWER8_VECTOR__)
49#ifndef SIMDJSON_EXPERIMENTAL_HAS_PPC64
50#define SIMDJSON_EXPERIMENTAL_HAS_PPC64 1
53#if SIMDJSON_EXPERIMENTAL_HAS_NEON
59#if SIMDJSON_EXPERIMENTAL_HAS_SSE2
68#if SIMDJSON_EXPERIMENTAL_HAS_LSX
71#if SIMDJSON_EXPERIMENTAL_HAS_LASX
72#include <lasxintrin.h>
74#if SIMDJSON_EXPERIMENTAL_HAS_RVV
75#include <riscv_vector.h>
77#if SIMDJSON_EXPERIMENTAL_HAS_PPC64
89namespace SIMDJSON_IMPLEMENTATION {
92static SIMDJSON_CONSTEXPR_LAMBDA std::array<uint8_t, 256>
93 json_quotable_character = {
94 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
95 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
96 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
97 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
98 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
99 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
100 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
101 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
102 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
103 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
104 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
124SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline
size_t
125find_next_json_quotable_character_scalar(
const std::string_view view,
126 size_t location)
noexcept {
127 for (
auto pos = view.begin() + location; pos != view.end(); ++pos) {
128 if (json_quotable_character[
static_cast<uint8_t
>(*pos)]) {
129 return pos - view.begin();
132 return size_t(view.size());
138#if SIMDJSON_EXPERIMENTAL_HAS_NEON
139simdjson_inline
size_t
140find_next_json_quotable_character(
const std::string_view view,
141 size_t location)
noexcept {
142 const size_t len = view.size();
144 reinterpret_cast<const uint8_t *
>(view.data()) + location;
145 size_t remaining = len - location;
148 uint8x16_t v34 = vdupq_n_u8(34);
149 uint8x16_t v92 = vdupq_n_u8(92);
150 uint8x16_t v32 = vdupq_n_u8(32);
152 while (remaining >= 16) {
153 uint8x16_t word = vld1q_u8(ptr);
156 uint8x16_t needs_escape = vceqq_u8(word, v34);
157 needs_escape = vorrq_u8(needs_escape, vceqq_u8(word, v92));
158 needs_escape = vorrq_u8(needs_escape, vcltq_u8(word, v32));
160 const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(needs_escape), 4);
161 const uint64_t mask = vget_lane_u64(vreinterpret_u64_u8(res), 0);
163 size_t offset = ptr -
reinterpret_cast<const uint8_t *
>(view.data());
164 auto trailing_zero = trailing_zeroes(mask);
165 return offset + (trailing_zero >> 2);
172 size_t current = len - remaining;
173 return find_next_json_quotable_character_scalar(view, current);
175#elif SIMDJSON_EXPERIMENTAL_HAS_SSE2
176simdjson_inline
size_t
177find_next_json_quotable_character(
const std::string_view view,
178 size_t location)
noexcept {
179 const size_t len = view.size();
181 reinterpret_cast<const uint8_t *
>(view.data()) + location;
182 size_t remaining = len - location;
185 __m128i v34 = _mm_set1_epi8(34);
186 __m128i v92 = _mm_set1_epi8(92);
187 __m128i v31 = _mm_set1_epi8(31);
189 while (remaining >= 16) {
190 __m128i word = _mm_loadu_si128(
reinterpret_cast<const __m128i *
>(ptr));
193 __m128i needs_escape = _mm_cmpeq_epi8(word, v34);
194 needs_escape = _mm_or_si128(needs_escape, _mm_cmpeq_epi8(word, v92));
195 needs_escape = _mm_or_si128(
197 _mm_cmpeq_epi8(_mm_subs_epu8(word, v31), _mm_setzero_si128()));
199 int mask = _mm_movemask_epi8(needs_escape);
202 size_t offset = ptr -
reinterpret_cast<const uint8_t *
>(view.data());
203 return offset + trailing_zeroes(mask);
210 size_t current = len - remaining;
211 return find_next_json_quotable_character_scalar(view, current);
213#elif SIMDJSON_EXPERIMENTAL_HAS_LASX
214simdjson_inline
size_t
215find_next_json_quotable_character(
const std::string_view view,
216 size_t location)
noexcept {
217 const size_t len = view.size();
219 reinterpret_cast<const uint8_t *
>(view.data()) + location;
220 size_t remaining = len - location;
223 __m256i v34 = __lasx_xvreplgr2vr_b(34);
224 __m256i v92 = __lasx_xvreplgr2vr_b(92);
225 __m256i v32 = __lasx_xvreplgr2vr_b(32);
227 while (remaining >= 32) {
228 __m256i word = __lasx_xvld(ptr, 0);
231 __m256i needs_escape = __lasx_xvseq_b(word, v34);
232 needs_escape = __lasx_xvor_v(needs_escape, __lasx_xvseq_b(word, v92));
233 needs_escape = __lasx_xvor_v(needs_escape, __lasx_xvslt_bu(word, v32));
235 if (!__lasx_xbz_v(needs_escape)) {
237 uint64_t lane0 = __lasx_xvpickve2gr_du(needs_escape, 0);
238 uint64_t lane1 = __lasx_xvpickve2gr_du(needs_escape, 1);
239 uint64_t lane2 = __lasx_xvpickve2gr_du(needs_escape, 2);
240 uint64_t lane3 = __lasx_xvpickve2gr_du(needs_escape, 3);
241 size_t offset = ptr -
reinterpret_cast<const uint8_t *
>(view.data());
243 return offset + trailing_zeroes(lane0) / 8;
244 }
else if (lane1 != 0) {
245 return offset + 8 + trailing_zeroes(lane1) / 8;
246 }
else if (lane2 != 0) {
247 return offset + 16 + trailing_zeroes(lane2) / 8;
249 return offset + 24 + trailing_zeroes(lane3) / 8;
255 size_t current = len - remaining;
256 return find_next_json_quotable_character_scalar(view, current);
258#elif SIMDJSON_EXPERIMENTAL_HAS_LSX
259simdjson_inline
size_t
260find_next_json_quotable_character(
const std::string_view view,
261 size_t location)
noexcept {
262 const size_t len = view.size();
264 reinterpret_cast<const uint8_t *
>(view.data()) + location;
265 size_t remaining = len - location;
268 __m128i v34 = __lsx_vreplgr2vr_b(34);
269 __m128i v92 = __lsx_vreplgr2vr_b(92);
270 __m128i v32 = __lsx_vreplgr2vr_b(32);
272 while (remaining >= 16){
273 __m128i word = __lsx_vld(ptr, 0);
276 __m128i needs_escape = __lsx_vseq_b(word, v34);
277 needs_escape = __lsx_vor_v(needs_escape, __lsx_vseq_b(word, v92));
278 needs_escape = __lsx_vor_v(needs_escape, __lsx_vslt_bu(word, v32));
280 if (!__lsx_bz_v(needs_escape)){
283 uint64_t lo = __lsx_vpickve2gr_du(needs_escape,0);
284 uint64_t hi = __lsx_vpickve2gr_du(needs_escape,1);
285 size_t offset = ptr -
reinterpret_cast<const uint8_t *
>(view.data());
287 return offset + trailing_zeroes(lo) / 8;
289 return offset + 8 + trailing_zeroes(hi) / 8;
295 size_t current = len - remaining;
296 return find_next_json_quotable_character_scalar(view, current);
298#elif SIMDJSON_EXPERIMENTAL_HAS_RVV
299simdjson_inline
size_t
300find_next_json_quotable_character(
const std::string_view view,
301 size_t location)
noexcept {
302 const size_t len = view.size();
304 reinterpret_cast<const uint8_t *
>(view.data()) + location;
305 size_t remaining = len - location;
307 while (remaining > 0) {
308 size_t vl = __riscv_vsetvl_e8m1(remaining);
309 vuint8m1_t word = __riscv_vle8_v_u8m1(ptr, vl);
312 vbool8_t needs_escape = __riscv_vmseq(word, (uint8_t)34, vl);
313 needs_escape = __riscv_vmor(needs_escape,
314 __riscv_vmseq(word, (uint8_t)92, vl), vl);
315 needs_escape = __riscv_vmor(needs_escape,
316 __riscv_vmsltu(word, (uint8_t)32, vl), vl);
318 long first = __riscv_vfirst(needs_escape, vl);
320 size_t offset = ptr -
reinterpret_cast<const uint8_t *
>(view.data());
321 return offset + first;
329#elif SIMDJSON_EXPERIMENTAL_HAS_PPC64
330simdjson_inline
size_t
331find_next_json_quotable_character(
const std::string_view view,
332 size_t location)
noexcept {
333 const size_t len = view.size();
335 reinterpret_cast<const uint8_t *
>(view.data()) + location;
336 size_t remaining = len - location;
339 __vector
unsigned char v34 = vec_splats((
unsigned char)34);
340 __vector
unsigned char v92 = vec_splats((
unsigned char)92);
341 __vector
unsigned char v32 = vec_splats((
unsigned char)32);
344 const __vector
unsigned char perm_mask = {0x78, 0x70, 0x68, 0x60, 0x58, 0x50,
345 0x48, 0x40, 0x38, 0x30, 0x28, 0x20,
346 0x18, 0x10, 0x08, 0x00};
348 while (remaining >= 16) {
349 __vector
unsigned char word =
350 vec_vsx_ld(0,
reinterpret_cast<const unsigned char *
>(ptr));
353 __vector
unsigned char needs_escape =
354 (__vector
unsigned char)vec_cmpeq(word, v34);
355 needs_escape = vec_or(needs_escape,
356 (__vector
unsigned char)vec_cmpeq(word, v92));
357 needs_escape = vec_or(needs_escape,
358 (__vector
unsigned char)vec_cmplt(word, v32));
360 __vector
unsigned long long result =
361 (__vector
unsigned long long)vec_vbpermq(needs_escape, perm_mask);
362#ifdef __LITTLE_ENDIAN__
363 unsigned int mask =
static_cast<unsigned int>(result[1]);
365 unsigned int mask =
static_cast<unsigned int>(result[0]);
368 size_t offset = ptr -
reinterpret_cast<const uint8_t *
>(view.data());
369 return offset + __builtin_ctz(mask);
376 size_t current = len - remaining;
377 return find_next_json_quotable_character_scalar(view, current);
380SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline
size_t
381find_next_json_quotable_character(
const std::string_view view,
382 size_t location)
noexcept {
383 return find_next_json_quotable_character_scalar(view, location);
387SIMDJSON_CONSTEXPR_LAMBDA
static std::string_view control_chars[] = {
388 "\\u0000",
"\\u0001",
"\\u0002",
"\\u0003",
"\\u0004",
"\\u0005",
"\\u0006",
389 "\\u0007",
"\\b",
"\\t",
"\\n",
"\\u000b",
"\\f",
"\\r",
390 "\\u000e",
"\\u000f",
"\\u0010",
"\\u0011",
"\\u0012",
"\\u0013",
"\\u0014",
391 "\\u0015",
"\\u0016",
"\\u0017",
"\\u0018",
"\\u0019",
"\\u001a",
"\\u001b",
392 "\\u001c",
"\\u001d",
"\\u001e",
"\\u001f"};
399SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline
void escape_json_char(
char c,
char *&out) {
401 memcpy(out,
"\\\"", 2);
403 }
else if (c ==
'\\') {
404 memcpy(out,
"\\\\", 2);
407 std::string_view v = control_chars[uint8_t(c)];
408 memcpy(out, v.data(), v.size());
413#if SIMDJSON_EXPERIMENTAL_HAS_SSE2 || SIMDJSON_EXPERIMENTAL_HAS_NEON
414#define SIMDJSON_BUILDER_HAS_BLOCK_ESCAPE 1
417#if SIMDJSON_BUILDER_HAS_BLOCK_ESCAPE
419#if SIMDJSON_EXPERIMENTAL_HAS_SSE2
421using escape_vector = __m128i;
423static constexpr unsigned escape_mask_bits = 1;
425simdjson_inline escape_vector escape_load16(
const uint8_t *p)
noexcept {
426 return _mm_loadu_si128(
reinterpret_cast<const __m128i *
>(p));
429simdjson_inline
void escape_store16(
char *out, escape_vector v)
noexcept {
430 _mm_storeu_si128(
reinterpret_cast<__m128i *
>(out), v);
434simdjson_inline escape_vector escape_load8x2(
const uint8_t *a,
435 const uint8_t *b)
noexcept {
436 return _mm_unpacklo_epi64(
437 _mm_loadl_epi64(
reinterpret_cast<const __m128i *
>(a)),
438 _mm_loadl_epi64(
reinterpret_cast<const __m128i *
>(b)));
443simdjson_inline escape_vector escape_load4x2(
const uint8_t *a,
444 const uint8_t *b)
noexcept {
448 return _mm_unpacklo_epi32(_mm_cvtsi32_si128(a32), _mm_cvtsi32_si128(b32));
453simdjson_inline escape_vector escape_flags(escape_vector v)
noexcept {
454 const __m128i v34 = _mm_set1_epi8(34);
455 const __m128i v92 = _mm_set1_epi8(92);
456 const __m128i v31 = _mm_set1_epi8(31);
457 __m128i needs_escape = _mm_cmpeq_epi8(v, v34);
458 needs_escape = _mm_or_si128(needs_escape, _mm_cmpeq_epi8(v, v92));
460 needs_escape, _mm_cmpeq_epi8(_mm_subs_epu8(v, v31), _mm_setzero_si128()));
466simdjson_inline
bool escape_any(escape_vector flags)
noexcept {
467 return _mm_movemask_epi8(flags) != 0;
471simdjson_inline uint64_t escape_bitmask(escape_vector flags)
noexcept {
472 return uint64_t(uint32_t(_mm_movemask_epi8(flags)));
477using escape_vector = uint8x16_t;
478static constexpr unsigned escape_mask_bits = 4;
480simdjson_inline escape_vector escape_load16(
const uint8_t *p)
noexcept {
484simdjson_inline
void escape_store16(
char *out, escape_vector v)
noexcept {
485 vst1q_u8(
reinterpret_cast<uint8_t *
>(out), v);
488simdjson_inline escape_vector escape_load8x2(
const uint8_t *a,
489 const uint8_t *b)
noexcept {
493 return vreinterpretq_u8_u64(vsetq_lane_u64(b64, vdupq_n_u64(a64), 1));
496simdjson_inline escape_vector escape_load4x2(
const uint8_t *a,
497 const uint8_t *b)
noexcept {
501 return vreinterpretq_u8_u32(vsetq_lane_u32(b32, vdupq_n_u32(a32), 1));
504simdjson_inline escape_vector escape_flags(escape_vector v)
noexcept {
505 uint8x16_t needs_escape = vceqq_u8(v, vdupq_n_u8(34));
506 needs_escape = vorrq_u8(needs_escape, vceqq_u8(v, vdupq_n_u8(92)));
507 return vorrq_u8(needs_escape, vcltq_u8(v, vdupq_n_u8(32)));
510simdjson_inline
bool escape_any(escape_vector flags)
noexcept {
511 return vmaxvq_u32(vreinterpretq_u32_u8(flags)) != 0;
516simdjson_inline uint64_t escape_bitmask(escape_vector flags)
noexcept {
517 uint8x8_t narrowed = vshrn_n_u16(vreinterpretq_u16_u8(flags), 4);
518 return vget_lane_u64(vreinterpret_u64_u8(narrowed), 0);
524simdjson_inline uint64_t escape_mask(escape_vector v)
noexcept {
525 return escape_bitmask(escape_flags(v));
530simdjson_inline
void copy_lt16(
char *dst,
const uint8_t *src,
534 memcpy(dst + n - 8, src + n - 8, 8);
537 memcpy(dst + n - 4, src + n - 4, 4);
539 dst[0] = char(src[0]);
540 dst[n >> 1] = char(src[n >> 1]);
541 dst[n - 1] = char(src[n - 1]);
549simdjson_never_inline
char *escape_block(
const uint8_t *src,
char *out,
550 size_t i,
size_t blockend,
551 uint64_t m)
noexcept {
552 constexpr uint64_t lane = (uint64_t(1) << escape_mask_bits) - 1;
556 const size_t tz = trailing_zeroes(m);
557 const size_t next = i + tz / escape_mask_bits;
559 copy_lt16(out, src + pos, next - pos);
561 escape_json_char(
char(src[next]), out);
566 copy_lt16(out, src + pos, blockend - pos);
567 return out + (blockend - pos);
572simdjson_really_inline
size_t write_string_escaped(
const std::string_view input,
char *out) {
573 const size_t len = input.size();
574 const uint8_t *src =
reinterpret_cast<const uint8_t *
>(input.data());
575 const char *
const initout = out;
578#if SIMDJSON_EXPERIMENTAL_HAS_SSE2 && defined(__AVX2__)
579 while (i + 32 <= len) {
580 const __m256i word = _mm256_loadu_si256(
reinterpret_cast<const __m256i *
>(src + i));
581 const __m256i flags = _mm256_or_si256(
582 _mm256_or_si256(_mm256_cmpeq_epi8(word, _mm256_set1_epi8(34)),
583 _mm256_cmpeq_epi8(word, _mm256_set1_epi8(92))),
584 _mm256_cmpeq_epi8(_mm256_subs_epu8(word, _mm256_set1_epi8(31)),
585 _mm256_setzero_si256()));
586 const uint32_t mask = uint32_t(_mm256_movemask_epi8(flags));
587 if (simdjson_likely(mask == 0)) {
588 _mm256_storeu_si256(
reinterpret_cast<__m256i *
>(out), word);
591 for (
size_t half = 0; half < 32; half += 16) {
592 const uint64_t m = (mask >> half) & 0xFFFF;
594 escape_store16(out, escape_load16(src + i + half));
597 out = escape_block(src, out, i + half, i + half + 16, m);
604 while (i + 16 <= len) {
605 escape_vector word = escape_load16(src + i);
606 escape_vector flags = escape_flags(word);
607 if (simdjson_likely(!escape_any(flags))) {
608 escape_store16(out, word);
611 out = escape_block(src, out, i, i + 16, escape_bitmask(flags));
616 const size_t rem = len - i;
622 m = escape_mask(escape_load16(src + len - 16)) >>
623 (escape_mask_bits * (16 - rem));
624 }
else if (len >= 8) {
627 uint64_t mm = escape_mask(escape_load8x2(src, src + len - 8));
628 constexpr uint64_t low8 = (uint64_t(1) << (escape_mask_bits * 8)) - 1;
630 ((mm >> (escape_mask_bits * 8)) << (escape_mask_bits * (len - 8)));
631 }
else if (len >= 4) {
633 uint64_t mm = escape_mask(escape_load4x2(src, src + len - 4));
634 constexpr uint64_t low4 = (uint64_t(1) << (escape_mask_bits * 4)) - 1;
635 m = (mm & low4) | (((mm >> (escape_mask_bits * 4)) & low4)
636 << (escape_mask_bits * (len - 4)));
639 for (
size_t k = 0; k < len; k++) {
641 if (json_quotable_character[c]) {
642 escape_json_char(
char(c), out);
647 return size_t(out - initout);
650 copy_lt16(out, src + i, rem);
653 out = escape_block(src, out, i, len, m);
656 return size_t(out - initout);
663inline size_t write_string_escaped(
const std::string_view input,
char *out) {
664 size_t mysize = input.size();
667 size_t location = find_next_json_quotable_character(input, 0);
668 if (location == mysize) {
670 memcpy(out, input.data(), input.size());
674 const char *
const initout = out;
675 memcpy(out, input.data(), location);
677 escape_json_char(input[location], out);
679 while (location < mysize) {
680 size_t newlocation = find_next_json_quotable_character(input, location);
681 memcpy(out, input.data() + location, newlocation - location);
682 out += newlocation - location;
683 location = newlocation;
684 if (location == mysize) {
687 escape_json_char(input[location], out);
690 return size_t(out - initout);
694#undef SIMDJSON_BUILDER_HAS_BLOCK_ESCAPE
697simdjson_inline string_builder::string_builder(
size_t initial_capacity)
698 : buffer(new(std::nothrow) char[initial_capacity]), position(0),
699 capacity(buffer.get() != nullptr ? initial_capacity : 0),
700 is_valid(buffer.get() != nullptr) {}
702simdjson_inline
bool string_builder::capacity_check(
size_t upcoming_bytes) {
706 if (simdjson_likely(upcoming_bytes <= capacity - position)) {
710 if (simdjson_unlikely(position + upcoming_bytes < position)) {
714 grow_buffer((std::max)(capacity * 2, position + upcoming_bytes));
719inline void string_builder::grow_buffer(
size_t desired_capacity) {
723 std::unique_ptr<char[]> new_buffer(
new (std::nothrow)
char[desired_capacity]);
724 if (new_buffer.get() ==
nullptr) {
728 std::memcpy(new_buffer.get(), buffer.get(), position);
729 buffer.swap(new_buffer);
730 capacity = desired_capacity;
733simdjson_inline
void string_builder::set_valid(
bool valid)
noexcept {
744simdjson_inline
size_t string_builder::size() const noexcept {
748simdjson_inline
void string_builder::append(
char c)
noexcept {
749 if (capacity_check(1)) {
750 buffer.get()[position++] = c;
754simdjson_inline
void string_builder::append_null() noexcept {
755 constexpr char null_literal[] =
"null";
756 constexpr size_t null_len =
sizeof(null_literal) - 1;
757 if (capacity_check(null_len)) {
758 std::memcpy(buffer.get() + position, null_literal, null_len);
759 position += null_len;
763simdjson_inline
void string_builder::clear() noexcept {
776static const char jeaiii_dd[201] =
777 "00010203040506070809101112131415161718192021222324252627282930313233343536373839"
778 "40414243444546474849505152535455565758596061626364656667686970717273747576777879"
779 "8081828384858687888990919293949596979899";
780static const char jeaiii_fd[201] =
781 "0\0" "1\0" "2\0" "3\0" "4\0" "5\0" "6\0" "7\0" "8\0" "9\0"
782 "10111213141516171819202122232425262728293031323334353637383940414243444546474849"
783 "50515253545556575859606162636465666768697071727374757677787980818283848586878889"
784 "90919293949596979899";
786simdjson_really_inline
void jeaiii_write_dd(
char *p, uint64_t k)
noexcept {
787 std::memcpy(p, &jeaiii_dd[2 * k], 2);
789simdjson_really_inline
void jeaiii_write_fd(
char *p, uint64_t k)
noexcept {
790 std::memcpy(p, &jeaiii_fd[2 * k], 2);
794simdjson_really_inline
char *jeaiii_lt1e8(
char *b, uint32_t n)
noexcept {
795 constexpr uint64_t mask24 = (uint64_t(1) << 24) - 1;
796 constexpr uint64_t mask32 = (uint64_t(1) << 32) - 1;
798 jeaiii_write_fd(b, n);
799 return n < 10 ? b + 1 : b + 2;
803 const uint32_t f0 = uint32_t(10 * (1 << 24) / 1e3 + 1) * n;
804 jeaiii_write_fd(b, f0 >> 24);
806 const uint32_t f2 = uint32_t(f0 & mask24) * 100;
807 jeaiii_write_dd(b + 2, f2 >> 24);
810 const uint64_t f0 = uint64_t(10 * (1ull << 32) / 1e5 + 1) * n;
811 jeaiii_write_fd(b, f0 >> 32);
813 const uint64_t f2 = (f0 & mask32) * 100;
814 jeaiii_write_dd(b + 2, f2 >> 32);
815 const uint64_t f4 = (f2 & mask32) * 100;
816 jeaiii_write_dd(b + 4, f4 >> 32);
819 const uint64_t f0 = uint64_t(10 * (1ull << 48) / 1e7 + 1) * n >> 16;
820 jeaiii_write_fd(b, f0 >> 32);
822 const uint64_t f2 = (f0 & mask32) * 100;
823 jeaiii_write_dd(b + 2, f2 >> 32);
824 const uint64_t f4 = (f2 & mask32) * 100;
825 jeaiii_write_dd(b + 4, f4 >> 32);
826 const uint64_t f6 = (f4 & mask32) * 100;
827 jeaiii_write_dd(b + 6, f6 >> 32);
832simdjson_really_inline
char *jeaiii_8_digits(
char *b, uint32_t z)
noexcept {
833 constexpr uint64_t mask32 = (uint64_t(1) << 32) - 1;
834 const uint64_t f0 = (uint64_t((1ull << 48) / 1e6 + 1) * z >> 16) + 1;
835 jeaiii_write_dd(b, f0 >> 32);
836 const uint64_t f2 = (f0 & mask32) * 100;
837 jeaiii_write_dd(b + 2, f2 >> 32);
838 const uint64_t f4 = (f2 & mask32) * 100;
839 jeaiii_write_dd(b + 4, f4 >> 32);
840 const uint64_t f6 = (f4 & mask32) * 100;
841 jeaiii_write_dd(b + 6, f6 >> 32);
846simdjson_really_inline
char *jeaiii_9_or_10(
char *b, uint64_t n)
noexcept {
847 constexpr uint64_t mask57 = (uint64_t(1) << 57) - 1;
848 const uint64_t f0 = uint64_t(10 * (1ull << 57) / 1e9 + 1) * n;
849 jeaiii_write_fd(b, f0 >> 57);
851 const uint64_t f2 = (f0 & mask57) * 100;
852 jeaiii_write_dd(b + 2, f2 >> 57);
853 const uint64_t f4 = (f2 & mask57) * 100;
854 jeaiii_write_dd(b + 4, f4 >> 57);
855 const uint64_t f6 = (f4 & mask57) * 100;
856 jeaiii_write_dd(b + 6, f6 >> 57);
857 const uint64_t f8 = (f6 & mask57) * 100;
858 jeaiii_write_dd(b + 8, f8 >> 57);
862simdjson_really_inline
char *write_uint_jeaiii(
char *b, uint64_t n)
noexcept {
864 return jeaiii_lt1e8(b, uint32_t(n));
866 if (n < (uint64_t(1) << 32)) {
867 return jeaiii_9_or_10(b, n);
870 const uint32_t z = uint32_t(n % 100000000);
871 uint64_t u = n / 100000000;
874 b = jeaiii_lt1e8(b, uint32_t(u));
875 }
else if (u < (uint64_t(1) << 32)) {
876 b = jeaiii_9_or_10(b, u);
879 const uint32_t y = uint32_t(u % 100000000);
881 b = jeaiii_lt1e8(b, uint32_t(u));
882 b = jeaiii_8_digits(b, y);
884 return jeaiii_8_digits(b, z);
889simdjson_inline
char *write_double(
char *p,
double v)
noexcept {
890#if SIMDJSON_ENABLE_NAN_INF
891 if (simdjson_unlikely(!std::isfinite(v))) {
893 std::memcpy(p,
"NaN", 3);
899 std::memcpy(p,
"Infinity", 8);
903 return simdjson::internal::to_chars(p,
nullptr, v);
907template <
typename number_type,
typename>
908simdjson_inline
void string_builder::append(number_type v)
noexcept {
909 static_assert(std::is_same<number_type, bool>::value ||
910 std::is_integral<number_type>::value ||
911 std::is_floating_point<number_type>::value,
912 "Unsupported number type");
914 SIMDJSON_IF_CONSTEXPR(std::is_same<number_type, bool>::value) {
916 constexpr char true_literal[] =
"true";
917 constexpr size_t true_len =
sizeof(true_literal) - 1;
918 if (capacity_check(true_len)) {
919 std::memcpy(buffer.get() + position, true_literal, true_len);
920 position += true_len;
923 constexpr char false_literal[] =
"false";
924 constexpr size_t false_len =
sizeof(false_literal) - 1;
925 if (capacity_check(false_len)) {
926 std::memcpy(buffer.get() + position, false_literal, false_len);
927 position += false_len;
931 else SIMDJSON_IF_CONSTEXPR(std::is_unsigned<number_type>::value) {
932 constexpr size_t max_number_size = 20;
933 if (capacity_check(max_number_size)) {
934 using unsigned_type =
typename std::make_unsigned<number_type>::type;
935 char* end = internal::write_uint_jeaiii(
936 buffer.get() + position,
937 static_cast<uint64_t
>(
static_cast<unsigned_type
>(v)));
938 position = end - buffer.get();
941 else SIMDJSON_IF_CONSTEXPR(std::is_integral<number_type>::value) {
943 constexpr size_t max_number_size = 20;
944 if (capacity_check(max_number_size)) {
945 using unsigned_type =
typename std::make_unsigned<number_type>::type;
946 bool negative = v < 0;
948 unsigned_type pv = negative
949 ? unsigned_type(0) -
static_cast<unsigned_type
>(v)
950 :
static_cast<unsigned_type
>(v);
952 buffer.get()[position] =
'-';
953 position += negative;
954 char* end = internal::write_uint_jeaiii(
955 buffer.get() + position,
static_cast<uint64_t
>(pv));
956 position = end - buffer.get();
959 else SIMDJSON_IF_CONSTEXPR(std::is_floating_point<number_type>::value) {
963 constexpr size_t max_number_size = simdjson::internal::to_chars_buffer_size;
964 if (capacity_check(max_number_size)) {
965#if SIMDJSON_ENABLE_NAN_INF
967 if (simdjson_unlikely(!std::isfinite(v))) {
969 constexpr char nan_literal[] =
"NaN";
970 constexpr size_t nan_len =
sizeof(nan_literal) - 1;
972 std::memcpy(buffer.get() + position, nan_literal, nan_len);
975 constexpr char inf_literal[] =
"Infinity";
976 constexpr size_t inf_len =
sizeof(inf_literal) - 1;
978 buffer.get()[position] =
'-';
981 std::memcpy(buffer.get() + position, inf_literal, inf_len);
989 char *end = simdjson::internal::to_chars(buffer.get() + position,
nullptr,
991 position = end - buffer.get();
997string_builder::escape_and_append(std::string_view input)
noexcept {
1000 if (input.size() > (std::numeric_limits<size_t>::max)() / 6) {
1004 if (capacity_check(6 * input.size())) {
1005 position += write_string_escaped(input, buffer.get() + position);
1010string_builder::escape_and_append_with_quotes(std::string_view input)
noexcept {
1013 if (input.size() > ((std::numeric_limits<size_t>::max)() - 2) / 6) {
1017 if (capacity_check(2 + 6 * input.size())) {
1018 buffer.get()[position++] =
'"';
1019 position += write_string_escaped(input, buffer.get() + position);
1020 buffer.get()[position++] =
'"';
1025string_builder::escape_and_append_with_quotes(
char input)
noexcept {
1027 if (capacity_check(2 + 6 * 1)) {
1028 buffer.get()[position++] =
'"';
1029 std::string_view cinput(&input, 1);
1030 position += write_string_escaped(cinput, buffer.get() + position);
1031 buffer.get()[position++] =
'"';
1036string_builder::escape_and_append_with_quotes(
const char *input)
noexcept {
1037 std::string_view cinput(input);
1038 escape_and_append_with_quotes(cinput);
1040#if SIMDJSON_SUPPORTS_CONCEPTS
1041template <constevalutil::fixed_
string key>
1042simdjson_inline
void string_builder::escape_and_append_with_quotes() noexcept {
1043 escape_and_append_with_quotes(constevalutil::string_constant<key>::value);
1047simdjson_inline
void string_builder::append_raw(
const char *c)
noexcept {
1050 size_t len = std::char_traits<char>::length(c);
1055string_builder::append_raw(std::string_view input)
noexcept {
1056 if (capacity_check(input.size())) {
1057 std::memcpy(buffer.get() + position, input.data(), input.size());
1058 position += input.size();
1062simdjson_inline
void string_builder::append_raw(
const char *str,
1063 size_t len)
noexcept {
1064 if (capacity_check(len)) {
1065 std::memcpy(buffer.get() + position, str, len);
1071simdjson_inline
void string_builder::append_raw_n(
const char *str)
noexcept {
1072 if (capacity_check(N)) {
1073 std::memcpy(buffer.get() + position, str, N);
1077#if SIMDJSON_SUPPORTS_CONCEPTS
1079template <concepts::optional_type T>
1080 requires(!require_custom_serialization<T>)
1081simdjson_inline
void string_builder::append(
const T &opt) {
1089template <
typename T>
1090 requires(require_custom_serialization<T>)
1091simdjson_inline
void string_builder::append(T &&val) {
1092 serialize(*
this, std::forward<T>(val));
1095template <
typename T>
1096 requires(std::is_convertible<T, std::string_view>::value ||
1097 std::is_same<T, const char *>::value)
1098simdjson_inline
void string_builder::append(
const T &value) {
1099 escape_and_append_with_quotes(value);
1103#if SIMDJSON_SUPPORTS_RANGES && SIMDJSON_SUPPORTS_CONCEPTS
1105template <std::ranges::range R>
1106 requires(!std::is_convertible<R, std::string_view>::value && !concepts::optional_type<R> && !require_custom_serialization<R>)
1107simdjson_inline
void string_builder::append(
const R &range)
noexcept {
1108 auto it = std::ranges::begin(range);
1109 auto end = std::ranges::end(range);
1110 if constexpr (concepts::is_pair<std::ranges::range_value_t<R>>) {
1118 append_key_value(it->first, it->second);
1122 for (; it != end; ++it) {
1124 append_key_value(it->first, it->second);
1139 for (; it != end; ++it) {
1149#if SIMDJSON_EXCEPTIONS
1150simdjson_inline string_builder::operator std::string() const noexcept(false) {
1151 return std::string(
operator std::string_view());
1154simdjson_inline string_builder::operator std::string_view() const
1155 noexcept(false) simdjson_lifetime_bound {
1161string_builder::view() const noexcept {
1165 return std::string_view(buffer.get(), position);
1169 if (capacity_check(1)) {
1170 buffer.
get()[position] =
'\0';
1171 return buffer.get();
1176simdjson_inline
bool string_builder::validate_unicode() const noexcept {
1180simdjson_inline
void string_builder::start_object() noexcept {
1181 if (capacity_check(1)) {
1182 buffer.get()[position++] =
'{';
1186simdjson_inline
void string_builder::end_object() noexcept {
1187 if (capacity_check(1)) {
1188 buffer.get()[position++] =
'}';
1192simdjson_inline
void string_builder::start_array() noexcept {
1193 if (capacity_check(1)) {
1194 buffer.get()[position++] =
'[';
1198simdjson_inline
void string_builder::end_array() noexcept {
1199 if (capacity_check(1)) {
1200 buffer.get()[position++] =
']';
1204simdjson_inline
void string_builder::append_comma() noexcept {
1205 if (capacity_check(1)) {
1206 buffer.get()[position++] =
',';
1210simdjson_inline
void string_builder::append_colon() noexcept {
1211 if (capacity_check(1)) {
1212 buffer.get()[position++] =
':';
1216template <
typename key_type,
typename value_type>
1218string_builder::append_key_value(key_type key, value_type value)
noexcept {
1219 static_assert(std::is_same<key_type, const char *>::value ||
1220 std::is_convertible<key_type, std::string_view>::value,
1221 "Unsupported key type");
1222 escape_and_append_with_quotes(key);
1224 SIMDJSON_IF_CONSTEXPR(std::is_same<value_type, std::nullptr_t>::value) {
1227 else SIMDJSON_IF_CONSTEXPR(std::is_same<value_type, char>::value) {
1228 escape_and_append_with_quotes(value);
1230 else SIMDJSON_IF_CONSTEXPR(
1231 std::is_convertible<value_type, std::string_view>::value) {
1232 escape_and_append_with_quotes(value);
1234 else SIMDJSON_IF_CONSTEXPR(std::is_same<value_type, const char *>::value) {
1235 escape_and_append_with_quotes(value);
1242#if SIMDJSON_SUPPORTS_CONCEPTS
1243template <constevalutil::fixed_
string key,
typename value_type>
1245string_builder::append_key_value(value_type value)
noexcept {
1246 escape_and_append_with_quotes<key>();
1248 SIMDJSON_IF_CONSTEXPR(std::is_same<value_type, std::nullptr_t>::value) {
1251 else SIMDJSON_IF_CONSTEXPR(std::is_same<value_type, char>::value) {
1252 escape_and_append_with_quotes(value);
1254 else SIMDJSON_IF_CONSTEXPR(
1255 std::is_convertible<value_type, std::string_view>::value) {
1256 escape_and_append_with_quotes(value);
1258 else SIMDJSON_IF_CONSTEXPR(std::is_same<value_type, const char *>::value) {
1259 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.