5#ifndef SIMDJSON_GENERIC_STRING_BUILDER_INL_H
7#ifndef SIMDJSON_CONDITIONAL_INCLUDE
8#define SIMDJSON_GENERIC_STRING_BUILDER_INL_H
9#include "simdjson/generic/builder/json_string_builder.h"
18#if defined(__SSE2__) || defined(__x86_64__) || defined(__x86_64) || \
19 (defined(_M_AMD64) || defined(_M_X64) || \
20 (defined(_M_IX86_FP) && _M_IX86_FP == 2))
21#ifndef SIMDJSON_EXPERIMENTAL_HAS_SSE2
22#define SIMDJSON_EXPERIMENTAL_HAS_SSE2 1
26#if defined(__aarch64__) || defined(_M_ARM64)
27#ifndef SIMDJSON_EXPERIMENTAL_HAS_NEON
28#define SIMDJSON_EXPERIMENTAL_HAS_NEON 1
31#if defined(__loongarch_sx)
32#ifndef SIMDJSON_EXPERIMENTAL_HAS_LSX
33#define SIMDJSON_EXPERIMENTAL_HAS_LSX 1
36#if defined(__riscv_v_intrinsic) && __riscv_v_intrinsic >= 11000 && \
37 defined(__riscv_vector)
38#ifndef SIMDJSON_EXPERIMENTAL_HAS_RVV
39#define SIMDJSON_EXPERIMENTAL_HAS_RVV 1
42#if (defined(__PPC64__) || defined(_M_PPC64)) && defined(__ALTIVEC__)
43#ifndef SIMDJSON_EXPERIMENTAL_HAS_PPC64
44#define SIMDJSON_EXPERIMENTAL_HAS_PPC64 1
47#if SIMDJSON_EXPERIMENTAL_HAS_NEON
53#if SIMDJSON_EXPERIMENTAL_HAS_SSE2
59#if SIMDJSON_EXPERIMENTAL_HAS_LSX
62#if SIMDJSON_EXPERIMENTAL_HAS_RVV
63#include <riscv_vector.h>
65#if SIMDJSON_EXPERIMENTAL_HAS_PPC64
77namespace SIMDJSON_IMPLEMENTATION {
80static SIMDJSON_CONSTEXPR_LAMBDA std::array<uint8_t, 256>
81 json_quotable_character = {
82 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
83 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 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, 0, 0, 0, 0,
85 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0,
92 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
111SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline
bool
112simple_needs_escaping(std::string_view v) {
115 if (json_quotable_character[
static_cast<uint8_t
>(c)]) {
122#if SIMDJSON_EXPERIMENTAL_HAS_NEON
123simdjson_inline
bool fast_needs_escaping(std::string_view view) {
124 if (view.size() < 16) {
125 return simple_needs_escaping(view);
128 uint8x16_t running = vdupq_n_u8(0);
129 uint8x16_t v34 = vdupq_n_u8(34);
130 uint8x16_t v92 = vdupq_n_u8(92);
132 for (; i + 15 < view.size(); i += 16) {
133 uint8x16_t word = vld1q_u8((
const uint8_t *)view.data() + i);
134 running = vorrq_u8(running, vceqq_u8(word, v34));
135 running = vorrq_u8(running, vceqq_u8(word, v92));
136 running = vorrq_u8(running, vcltq_u8(word, vdupq_n_u8(32)));
138 if (i < view.size()) {
140 vld1q_u8((
const uint8_t *)view.data() + view.length() - 16);
141 running = vorrq_u8(running, vceqq_u8(word, v34));
142 running = vorrq_u8(running, vceqq_u8(word, v92));
143 running = vorrq_u8(running, vcltq_u8(word, vdupq_n_u8(32)));
145 return vmaxvq_u32(vreinterpretq_u32_u8(running)) != 0;
147#elif SIMDJSON_EXPERIMENTAL_HAS_SSE2
148simdjson_inline
bool fast_needs_escaping(std::string_view view) {
149 if (view.size() < 16) {
150 return simple_needs_escaping(view);
153 __m128i running = _mm_setzero_si128();
154 for (; i + 15 < view.size(); i += 16) {
157 _mm_loadu_si128(
reinterpret_cast<const __m128i *
>(view.data() + i));
158 running = _mm_or_si128(running, _mm_cmpeq_epi8(word, _mm_set1_epi8(34)));
159 running = _mm_or_si128(running, _mm_cmpeq_epi8(word, _mm_set1_epi8(92)));
160 running = _mm_or_si128(
161 running, _mm_cmpeq_epi8(_mm_subs_epu8(word, _mm_set1_epi8(31)),
162 _mm_setzero_si128()));
164 if (i < view.size()) {
165 __m128i word = _mm_loadu_si128(
166 reinterpret_cast<const __m128i *
>(view.data() + view.length() - 16));
167 running = _mm_or_si128(running, _mm_cmpeq_epi8(word, _mm_set1_epi8(34)));
168 running = _mm_or_si128(running, _mm_cmpeq_epi8(word, _mm_set1_epi8(92)));
169 running = _mm_or_si128(
170 running, _mm_cmpeq_epi8(_mm_subs_epu8(word, _mm_set1_epi8(31)),
171 _mm_setzero_si128()));
173 return _mm_movemask_epi8(running) != 0;
175#elif SIMDJSON_EXPERIMENTAL_HAS_PPC64
176simdjson_inline
bool fast_needs_escaping(std::string_view view) {
177 if (view.size() < 16) {
178 return simple_needs_escaping(view);
181 __vector
unsigned char running = vec_splats((
unsigned char)0);
182 __vector
unsigned char v34 = vec_splats((
unsigned char)34);
183 __vector
unsigned char v92 = vec_splats((
unsigned char)92);
184 __vector
unsigned char v32 = vec_splats((
unsigned char)32);
186 for (; i + 15 < view.size(); i += 16) {
187 __vector
unsigned char word =
188 vec_vsx_ld(0,
reinterpret_cast<const unsigned char *
>(view.data() + i));
189 running = vec_or(running, (__vector
unsigned char)vec_cmpeq(word, v34));
190 running = vec_or(running, (__vector
unsigned char)vec_cmpeq(word, v92));
191 running = vec_or(running,
192 (__vector
unsigned char)vec_cmplt(word, v32));
194 if (i < view.size()) {
195 __vector
unsigned char word = vec_vsx_ld(
196 0,
reinterpret_cast<const unsigned char *
>(view.data() + view.length() - 16));
197 running = vec_or(running, (__vector
unsigned char)vec_cmpeq(word, v34));
198 running = vec_or(running, (__vector
unsigned char)vec_cmpeq(word, v92));
199 running = vec_or(running,
200 (__vector
unsigned char)vec_cmplt(word, v32));
202 return !vec_all_eq(running, vec_splats((
unsigned char)0));
205simdjson_inline
bool fast_needs_escaping(std::string_view view) {
206 return simple_needs_escaping(view);
211SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline
size_t
212find_next_json_quotable_character_scalar(
const std::string_view view,
213 size_t location)
noexcept {
214 for (
auto pos = view.begin() + location; pos != view.end(); ++pos) {
215 if (json_quotable_character[
static_cast<uint8_t
>(*pos)]) {
216 return pos - view.begin();
219 return size_t(view.size());
225#if SIMDJSON_EXPERIMENTAL_HAS_NEON
226simdjson_inline
size_t
227find_next_json_quotable_character(
const std::string_view view,
228 size_t location)
noexcept {
229 const size_t len = view.size();
231 reinterpret_cast<const uint8_t *
>(view.data()) + location;
232 size_t remaining = len - location;
235 uint8x16_t v34 = vdupq_n_u8(34);
236 uint8x16_t v92 = vdupq_n_u8(92);
237 uint8x16_t v32 = vdupq_n_u8(32);
239 while (remaining >= 16) {
240 uint8x16_t word = vld1q_u8(ptr);
243 uint8x16_t needs_escape = vceqq_u8(word, v34);
244 needs_escape = vorrq_u8(needs_escape, vceqq_u8(word, v92));
245 needs_escape = vorrq_u8(needs_escape, vcltq_u8(word, v32));
247 const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(needs_escape), 4);
248 const uint64_t mask = vget_lane_u64(vreinterpret_u64_u8(res), 0);
250 size_t offset = ptr -
reinterpret_cast<const uint8_t *
>(view.data());
251 auto trailing_zero = trailing_zeroes(mask);
252 return offset + (trailing_zero >> 2);
259 size_t current = len - remaining;
260 return find_next_json_quotable_character_scalar(view, current);
262#elif SIMDJSON_EXPERIMENTAL_HAS_SSE2
263simdjson_inline
size_t
264find_next_json_quotable_character(
const std::string_view view,
265 size_t location)
noexcept {
266 const size_t len = view.size();
268 reinterpret_cast<const uint8_t *
>(view.data()) + location;
269 size_t remaining = len - location;
272 __m128i v34 = _mm_set1_epi8(34);
273 __m128i v92 = _mm_set1_epi8(92);
274 __m128i v31 = _mm_set1_epi8(31);
276 while (remaining >= 16) {
277 __m128i word = _mm_loadu_si128(
reinterpret_cast<const __m128i *
>(ptr));
280 __m128i needs_escape = _mm_cmpeq_epi8(word, v34);
281 needs_escape = _mm_or_si128(needs_escape, _mm_cmpeq_epi8(word, v92));
282 needs_escape = _mm_or_si128(
284 _mm_cmpeq_epi8(_mm_subs_epu8(word, v31), _mm_setzero_si128()));
286 int mask = _mm_movemask_epi8(needs_escape);
289 size_t offset = ptr -
reinterpret_cast<const uint8_t *
>(view.data());
290 return offset + trailing_zeroes(mask);
297 size_t current = len - remaining;
298 return find_next_json_quotable_character_scalar(view, current);
300#elif SIMDJSON_EXPERIMENTAL_HAS_LSX
301simdjson_inline
size_t
302find_next_json_quotable_character(
const std::string_view view,
303 size_t location)
noexcept {
304 const size_t len = view.size();
306 reinterpret_cast<const uint8_t *
>(view.data()) + location;
307 size_t remaining = len - location;
310 __m128i v34 = __lsx_vreplgr2vr_b(34);
311 __m128i v92 = __lsx_vreplgr2vr_b(92);
312 __m128i v32 = __lsx_vreplgr2vr_b(32);
314 while (remaining >= 16){
315 __m128i word = __lsx_vld(ptr, 0);
318 __m128i needs_escape = __lsx_vseq_b(word, v34);
319 needs_escape = __lsx_vor_v(needs_escape, __lsx_vseq_b(word, v92));
320 needs_escape = __lsx_vor_v(needs_escape, __lsx_vslt_bu(word, v32));
322 if (!__lsx_bz_v(needs_escape)){
325 uint64_t lo = __lsx_vpickve2gr_du(needs_escape,0);
326 uint64_t hi = __lsx_vpickve2gr_du(needs_escape,1);
327 size_t offset = ptr -
reinterpret_cast<const uint8_t *
>(view.data());
329 return offset + trailing_zeroes(lo) / 8;
331 return offset + 8 + trailing_zeroes(hi) / 8;
337 size_t current = len - remaining;
338 return find_next_json_quotable_character_scalar(view, current);
340#elif SIMDJSON_EXPERIMENTAL_HAS_RVV
341simdjson_inline
size_t
342find_next_json_quotable_character(
const std::string_view view,
343 size_t location)
noexcept {
344 const size_t len = view.size();
346 reinterpret_cast<const uint8_t *
>(view.data()) + location;
347 size_t remaining = len - location;
349 while (remaining > 0) {
350 size_t vl = __riscv_vsetvl_e8m1(remaining);
351 vuint8m1_t word = __riscv_vle8_v_u8m1(ptr, vl);
354 vbool8_t needs_escape = __riscv_vmseq(word, (uint8_t)34, vl);
355 needs_escape = __riscv_vmor(needs_escape,
356 __riscv_vmseq(word, (uint8_t)92, vl), vl);
357 needs_escape = __riscv_vmor(needs_escape,
358 __riscv_vmsltu(word, (uint8_t)32, vl), vl);
360 long first = __riscv_vfirst(needs_escape, vl);
362 size_t offset = ptr -
reinterpret_cast<const uint8_t *
>(view.data());
363 return offset + first;
371#elif SIMDJSON_EXPERIMENTAL_HAS_PPC64
372simdjson_inline
size_t
373find_next_json_quotable_character(
const std::string_view view,
374 size_t location)
noexcept {
375 const size_t len = view.size();
377 reinterpret_cast<const uint8_t *
>(view.data()) + location;
378 size_t remaining = len - location;
381 __vector
unsigned char v34 = vec_splats((
unsigned char)34);
382 __vector
unsigned char v92 = vec_splats((
unsigned char)92);
383 __vector
unsigned char v32 = vec_splats((
unsigned char)32);
386 const __vector
unsigned char perm_mask = {0x78, 0x70, 0x68, 0x60, 0x58, 0x50,
387 0x48, 0x40, 0x38, 0x30, 0x28, 0x20,
388 0x18, 0x10, 0x08, 0x00};
390 while (remaining >= 16) {
391 __vector
unsigned char word =
392 vec_vsx_ld(0,
reinterpret_cast<const unsigned char *
>(ptr));
395 __vector
unsigned char needs_escape =
396 (__vector
unsigned char)vec_cmpeq(word, v34);
397 needs_escape = vec_or(needs_escape,
398 (__vector
unsigned char)vec_cmpeq(word, v92));
399 needs_escape = vec_or(needs_escape,
400 (__vector
unsigned char)vec_cmplt(word, v32));
402 __vector
unsigned long long result =
403 (__vector
unsigned long long)vec_vbpermq(needs_escape, perm_mask);
404#ifdef __LITTLE_ENDIAN__
405 unsigned int mask =
static_cast<unsigned int>(result[1]);
407 unsigned int mask =
static_cast<unsigned int>(result[0]);
410 size_t offset = ptr -
reinterpret_cast<const uint8_t *
>(view.data());
411 return offset + __builtin_ctz(mask);
418 size_t current = len - remaining;
419 return find_next_json_quotable_character_scalar(view, current);
422SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline
size_t
423find_next_json_quotable_character(
const std::string_view view,
424 size_t location)
noexcept {
425 return find_next_json_quotable_character_scalar(view, location);
429SIMDJSON_CONSTEXPR_LAMBDA
static std::string_view control_chars[] = {
430 "\\u0000",
"\\u0001",
"\\u0002",
"\\u0003",
"\\u0004",
"\\u0005",
"\\u0006",
431 "\\u0007",
"\\b",
"\\t",
"\\n",
"\\u000b",
"\\f",
"\\r",
432 "\\u000e",
"\\u000f",
"\\u0010",
"\\u0011",
"\\u0012",
"\\u0013",
"\\u0014",
433 "\\u0015",
"\\u0016",
"\\u0017",
"\\u0018",
"\\u0019",
"\\u001a",
"\\u001b",
434 "\\u001c",
"\\u001d",
"\\u001e",
"\\u001f"};
441SIMDJSON_CONSTEXPR_LAMBDA simdjson_inline
void escape_json_char(
char c,
char *&out) {
443 memcpy(out,
"\\\"", 2);
445 }
else if (c ==
'\\') {
446 memcpy(out,
"\\\\", 2);
449 std::string_view v = control_chars[uint8_t(c)];
450 memcpy(out, v.data(), v.size());
457inline size_t write_string_escaped(
const std::string_view input,
char *out) {
458 size_t mysize = input.size();
461 size_t location = find_next_json_quotable_character(input, 0);
462 if (location == mysize) {
464 memcpy(out, input.data(), input.size());
468 const char *
const initout = out;
469 memcpy(out, input.data(), location);
471 escape_json_char(input[location], out);
473 while (location < mysize) {
474 size_t newlocation = find_next_json_quotable_character(input, location);
475 memcpy(out, input.data() + location, newlocation - location);
476 out += newlocation - location;
477 location = newlocation;
478 if (location == mysize) {
481 escape_json_char(input[location], out);
484 return out - initout;
487simdjson_inline string_builder::string_builder(
size_t initial_capacity)
488 : buffer(new(std::nothrow) char[initial_capacity]), position(0),
489 capacity(buffer.get() != nullptr ? initial_capacity : 0),
490 is_valid(buffer.get() != nullptr) {}
492simdjson_inline
bool string_builder::capacity_check(
size_t upcoming_bytes) {
496 if (simdjson_likely(upcoming_bytes <= capacity - position)) {
500 if (simdjson_unlikely(position + upcoming_bytes < position)) {
504 grow_buffer((std::max)(capacity * 2, position + upcoming_bytes));
509simdjson_inline
void string_builder::grow_buffer(
size_t desired_capacity) {
513 std::unique_ptr<char[]> new_buffer(
new (std::nothrow)
char[desired_capacity]);
514 if (new_buffer.get() ==
nullptr) {
518 std::memcpy(new_buffer.get(), buffer.get(), position);
519 buffer.swap(new_buffer);
520 capacity = desired_capacity;
523simdjson_inline
void string_builder::set_valid(
bool valid)
noexcept {
534simdjson_inline
size_t string_builder::size() const noexcept {
538simdjson_inline
void string_builder::append(
char c)
noexcept {
539 if (capacity_check(1)) {
540 buffer.get()[position++] = c;
544simdjson_inline
void string_builder::append_null() noexcept {
545 constexpr char null_literal[] =
"null";
546 constexpr size_t null_len =
sizeof(null_literal) - 1;
547 if (capacity_check(null_len)) {
548 std::memcpy(buffer.get() + position, null_literal, null_len);
549 position += null_len;
553simdjson_inline
void string_builder::clear() noexcept {
565template <
typename number_type,
typename =
typename std::enable_if<
566 std::is_unsigned<number_type>::value>::type>
567simdjson_really_inline
int int_log2(number_type x) {
568 return 63 - leading_zeroes(uint64_t(x) | 1);
571simdjson_really_inline
int fast_digit_count_32(uint32_t x) {
572 static uint64_t table[] = {
573 4294967296, 8589934582, 8589934582, 8589934582, 12884901788,
574 12884901788, 12884901788, 17179868184, 17179868184, 17179868184,
575 21474826480, 21474826480, 21474826480, 21474826480, 25769703776,
576 25769703776, 25769703776, 30063771072, 30063771072, 30063771072,
577 34349738368, 34349738368, 34349738368, 34349738368, 38554705664,
578 38554705664, 38554705664, 41949672960, 41949672960, 41949672960,
579 42949672960, 42949672960};
580 return uint32_t((x + table[int_log2(x)]) >> 32);
583simdjson_really_inline
int fast_digit_count_64(uint64_t x) {
584 static uint64_t table[] = {9,
600 99999999999999999ULL,
601 999999999999999999ULL,
602 9999999999999999999ULL};
603 int y = (19 * int_log2(x) >> 6);
608template <
typename number_type,
typename =
typename std::enable_if<
609 std::is_unsigned<number_type>::value>::type>
610simdjson_really_inline
size_t digit_count(number_type v)
noexcept {
611 static_assert(
sizeof(number_type) == 8 ||
sizeof(number_type) == 4 ||
612 sizeof(number_type) == 2 ||
sizeof(number_type) == 1,
613 "We only support 8-bit, 16-bit, 32-bit and 64-bit numbers");
614 SIMDJSON_IF_CONSTEXPR(
sizeof(number_type) <= 4) {
615 return fast_digit_count_32(
static_cast<uint32_t
>(v));
618 return fast_digit_count_64(
static_cast<uint64_t
>(v));
621static const char decimal_table[200] = {
622 0x30, 0x30, 0x30, 0x31, 0x30, 0x32, 0x30, 0x33, 0x30, 0x34, 0x30, 0x35,
623 0x30, 0x36, 0x30, 0x37, 0x30, 0x38, 0x30, 0x39, 0x31, 0x30, 0x31, 0x31,
624 0x31, 0x32, 0x31, 0x33, 0x31, 0x34, 0x31, 0x35, 0x31, 0x36, 0x31, 0x37,
625 0x31, 0x38, 0x31, 0x39, 0x32, 0x30, 0x32, 0x31, 0x32, 0x32, 0x32, 0x33,
626 0x32, 0x34, 0x32, 0x35, 0x32, 0x36, 0x32, 0x37, 0x32, 0x38, 0x32, 0x39,
627 0x33, 0x30, 0x33, 0x31, 0x33, 0x32, 0x33, 0x33, 0x33, 0x34, 0x33, 0x35,
628 0x33, 0x36, 0x33, 0x37, 0x33, 0x38, 0x33, 0x39, 0x34, 0x30, 0x34, 0x31,
629 0x34, 0x32, 0x34, 0x33, 0x34, 0x34, 0x34, 0x35, 0x34, 0x36, 0x34, 0x37,
630 0x34, 0x38, 0x34, 0x39, 0x35, 0x30, 0x35, 0x31, 0x35, 0x32, 0x35, 0x33,
631 0x35, 0x34, 0x35, 0x35, 0x35, 0x36, 0x35, 0x37, 0x35, 0x38, 0x35, 0x39,
632 0x36, 0x30, 0x36, 0x31, 0x36, 0x32, 0x36, 0x33, 0x36, 0x34, 0x36, 0x35,
633 0x36, 0x36, 0x36, 0x37, 0x36, 0x38, 0x36, 0x39, 0x37, 0x30, 0x37, 0x31,
634 0x37, 0x32, 0x37, 0x33, 0x37, 0x34, 0x37, 0x35, 0x37, 0x36, 0x37, 0x37,
635 0x37, 0x38, 0x37, 0x39, 0x38, 0x30, 0x38, 0x31, 0x38, 0x32, 0x38, 0x33,
636 0x38, 0x34, 0x38, 0x35, 0x38, 0x36, 0x38, 0x37, 0x38, 0x38, 0x38, 0x39,
637 0x39, 0x30, 0x39, 0x31, 0x39, 0x32, 0x39, 0x33, 0x39, 0x34, 0x39, 0x35,
638 0x39, 0x36, 0x39, 0x37, 0x39, 0x38, 0x39, 0x39,
642template <
typename number_type,
typename>
643simdjson_inline
void string_builder::append(number_type v)
noexcept {
644 static_assert(std::is_same<number_type, bool>::value ||
645 std::is_integral<number_type>::value ||
646 std::is_floating_point<number_type>::value,
647 "Unsupported number type");
649 SIMDJSON_IF_CONSTEXPR(std::is_same<number_type, bool>::value) {
651 constexpr char true_literal[] =
"true";
652 constexpr size_t true_len =
sizeof(true_literal) - 1;
653 if (capacity_check(true_len)) {
654 std::memcpy(buffer.get() + position, true_literal, true_len);
655 position += true_len;
658 constexpr char false_literal[] =
"false";
659 constexpr size_t false_len =
sizeof(false_literal) - 1;
660 if (capacity_check(false_len)) {
661 std::memcpy(buffer.get() + position, false_literal, false_len);
662 position += false_len;
666 else SIMDJSON_IF_CONSTEXPR(std::is_unsigned<number_type>::value) {
669 constexpr size_t max_number_size = 20;
670 if (capacity_check(max_number_size)) {
671 using unsigned_type =
typename std::make_unsigned<number_type>::type;
672 unsigned_type pv =
static_cast<unsigned_type
>(v);
673 size_t dc = internal::digit_count(pv);
674 char *write_pointer = buffer.get() + position + dc - 1;
677 while (pv >= 10000) {
678 unsigned_type q = pv / 10000;
679 unsigned_type r = pv % 10000;
680 unsigned_type r_hi = r / 100;
681 unsigned_type r_lo = r % 100;
683 memcpy(write_pointer - 1, &internal::decimal_table[r_lo * 2], 2);
684 memcpy(write_pointer - 3, &internal::decimal_table[r_hi * 2], 2);
691 memcpy(write_pointer - 1, &internal::decimal_table[(pv % 100) * 2], 2);
696 *write_pointer-- = char(
'0' + (pv % 10));
699 *write_pointer = char(
'0' + pv);
703 else SIMDJSON_IF_CONSTEXPR(std::is_integral<number_type>::value) {
705 constexpr size_t max_number_size = 20;
706 if (capacity_check(max_number_size)) {
707 using unsigned_type =
typename std::make_unsigned<number_type>::type;
708 bool negative = v < 0;
709 unsigned_type pv =
static_cast<unsigned_type
>(v);
713 size_t dc = internal::digit_count(pv);
715 buffer.get()[position] =
'-';
716 position += negative ? 1 : 0;
717 char *write_pointer = buffer.get() + position + dc - 1;
720 while (pv >= 10000) {
721 unsigned_type q = pv / 10000;
722 unsigned_type r = pv % 10000;
723 unsigned_type r_hi = r / 100;
724 unsigned_type r_lo = r % 100;
725 memcpy(write_pointer - 1, &internal::decimal_table[r_lo * 2], 2);
726 memcpy(write_pointer - 3, &internal::decimal_table[r_hi * 2], 2);
733 memcpy(write_pointer - 1, &internal::decimal_table[(pv % 100) * 2], 2);
738 *write_pointer-- = char(
'0' + (pv % 10));
741 *write_pointer = char(
'0' + pv);
745 else SIMDJSON_IF_CONSTEXPR(std::is_floating_point<number_type>::value) {
746 constexpr size_t max_number_size = 24;
747 if (capacity_check(max_number_size)) {
749 char *end = simdjson::internal::to_chars(buffer.get() + position,
nullptr,
751 position = end - buffer.get();
757string_builder::escape_and_append(std::string_view input)
noexcept {
760 if (input.size() > (std::numeric_limits<size_t>::max)() / 6) {
764 if (capacity_check(6 * input.size())) {
765 position += write_string_escaped(input, buffer.get() + position);
770string_builder::escape_and_append_with_quotes(std::string_view input)
noexcept {
773 if (input.size() > ((std::numeric_limits<size_t>::max)() - 2) / 6) {
777 if (capacity_check(2 + 6 * input.size())) {
778 buffer.get()[position++] =
'"';
779 position += write_string_escaped(input, buffer.get() + position);
780 buffer.get()[position++] =
'"';
785string_builder::escape_and_append_with_quotes(
char input)
noexcept {
787 if (capacity_check(2 + 6 * 1)) {
788 buffer.get()[position++] =
'"';
789 std::string_view cinput(&input, 1);
790 position += write_string_escaped(cinput, buffer.get() + position);
791 buffer.get()[position++] =
'"';
796string_builder::escape_and_append_with_quotes(
const char *input)
noexcept {
797 std::string_view cinput(input);
798 escape_and_append_with_quotes(cinput);
800#if SIMDJSON_SUPPORTS_CONCEPTS
801template <constevalutil::fixed_
string key>
802simdjson_inline
void string_builder::escape_and_append_with_quotes() noexcept {
803 escape_and_append_with_quotes(constevalutil::string_constant<key>::value);
807simdjson_inline
void string_builder::append_raw(
const char *c)
noexcept {
808 size_t len = std::strlen(c);
813string_builder::append_raw(std::string_view input)
noexcept {
814 if (capacity_check(input.size())) {
815 std::memcpy(buffer.get() + position, input.data(), input.size());
816 position += input.size();
820simdjson_inline
void string_builder::append_raw(
const char *str,
821 size_t len)
noexcept {
822 if (capacity_check(len)) {
823 std::memcpy(buffer.get() + position, str, len);
827#if SIMDJSON_SUPPORTS_CONCEPTS
829template <concepts::optional_type T>
830 requires(!require_custom_serialization<T>)
831simdjson_inline
void string_builder::append(
const T &opt) {
840 requires(require_custom_serialization<T>)
841simdjson_inline
void string_builder::append(T &&val) {
842 serialize(*
this, std::forward<T>(val));
846 requires(std::is_convertible<T, std::string_view>::value ||
847 std::is_same<T, const char *>::value)
848simdjson_inline
void string_builder::append(
const T &value) {
849 escape_and_append_with_quotes(value);
853#if SIMDJSON_SUPPORTS_RANGES && SIMDJSON_SUPPORTS_CONCEPTS
855template <std::ranges::range R>
856 requires(!std::is_convertible<R, std::string_view>::value && !require_custom_serialization<R>)
857simdjson_inline
void string_builder::append(
const R &range)
noexcept {
858 auto it = std::ranges::begin(range);
859 auto end = std::ranges::end(range);
860 if constexpr (concepts::is_pair<std::ranges::range_value_t<R>>) {
868 append_key_value(it->first, it->second);
872 for (; it != end; ++it) {
874 append_key_value(it->first, it->second);
889 for (; it != end; ++it) {
899#if SIMDJSON_EXCEPTIONS
900simdjson_inline string_builder::operator std::string() const noexcept(false) {
901 return std::string(
operator std::string_view());
904simdjson_inline string_builder::operator std::string_view() const
905 noexcept(false) simdjson_lifetime_bound {
911string_builder::view() const noexcept {
915 return std::string_view(buffer.get(), position);
919 if (capacity_check(1)) {
920 buffer.
get()[position] =
'\0';
926simdjson_inline
bool string_builder::validate_unicode() const noexcept {
930simdjson_inline
void string_builder::start_object() noexcept {
931 if (capacity_check(1)) {
932 buffer.get()[position++] =
'{';
936simdjson_inline
void string_builder::end_object() noexcept {
937 if (capacity_check(1)) {
938 buffer.get()[position++] =
'}';
942simdjson_inline
void string_builder::start_array() noexcept {
943 if (capacity_check(1)) {
944 buffer.get()[position++] =
'[';
948simdjson_inline
void string_builder::end_array() noexcept {
949 if (capacity_check(1)) {
950 buffer.get()[position++] =
']';
954simdjson_inline
void string_builder::append_comma() noexcept {
955 if (capacity_check(1)) {
956 buffer.get()[position++] =
',';
960simdjson_inline
void string_builder::append_colon() noexcept {
961 if (capacity_check(1)) {
962 buffer.get()[position++] =
':';
966template <
typename key_type,
typename value_type>
968string_builder::append_key_value(key_type key, value_type value)
noexcept {
969 static_assert(std::is_same<key_type, const char *>::value ||
970 std::is_convertible<key_type, std::string_view>::value,
971 "Unsupported key type");
972 escape_and_append_with_quotes(key);
974 SIMDJSON_IF_CONSTEXPR(std::is_same<value_type, std::nullptr_t>::value) {
977 else SIMDJSON_IF_CONSTEXPR(std::is_same<value_type, char>::value) {
978 escape_and_append_with_quotes(value);
980 else SIMDJSON_IF_CONSTEXPR(
981 std::is_convertible<value_type, std::string_view>::value) {
982 escape_and_append_with_quotes(value);
984 else SIMDJSON_IF_CONSTEXPR(std::is_same<value_type, const char *>::value) {
985 escape_and_append_with_quotes(value);
992#if SIMDJSON_SUPPORTS_CONCEPTS
993template <constevalutil::fixed_
string key,
typename value_type>
995string_builder::append_key_value(value_type value)
noexcept {
996 escape_and_append_with_quotes<key>();
998 SIMDJSON_IF_CONSTEXPR(std::is_same<value_type, std::nullptr_t>::value) {
1001 else SIMDJSON_IF_CONSTEXPR(std::is_same<value_type, char>::value) {
1002 escape_and_append_with_quotes(value);
1004 else SIMDJSON_IF_CONSTEXPR(
1005 std::is_convertible<value_type, std::string_view>::value) {
1006 escape_and_append_with_quotes(value);
1008 else SIMDJSON_IF_CONSTEXPR(std::is_same<value_type, const char *>::value) {
1009 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.