Skip to content

Commit bf67c96

Browse files
committed
Inline jsoncharutils per-implementation
1 parent 44b7a71 commit bf67c96

File tree

9 files changed

+143
-119
lines changed

9 files changed

+143
-119
lines changed

src/arm64/dom_parser_implementation.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "arm64/begin_implementation.h"
22
#include "arm64/dom_parser_implementation.h"
3+
#include "generic/stage2/jsoncharutils.h"
34

45
//
56
// Stage 1

src/fallback/dom_parser_implementation.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "fallback/begin_implementation.h"
22
#include "fallback/dom_parser_implementation.h"
3+
#include "generic/stage2/jsoncharutils.h"
34

45
//
56
// Stage 1

src/generic/stage2/jsoncharutils.h

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
namespace simdjson {
2+
namespace SIMDJSON_IMPLEMENTATION {
3+
namespace stage2 {
4+
5+
// return non-zero if not a structural or whitespace char
6+
// zero otherwise
7+
really_inline uint32_t is_not_structural_or_whitespace_or_null(uint8_t c) {
8+
return structural_or_whitespace_or_null_negated[c];
9+
}
10+
11+
// return non-zero if not a structural or whitespace char
12+
// zero otherwise
13+
really_inline uint32_t is_not_structural_or_whitespace(uint8_t c) {
14+
return structural_or_whitespace_negated[c];
15+
}
16+
17+
really_inline uint32_t is_structural_or_whitespace_or_null(uint8_t c) {
18+
return structural_or_whitespace_or_null[c];
19+
}
20+
21+
really_inline uint32_t is_structural_or_whitespace(uint8_t c) {
22+
return structural_or_whitespace[c];
23+
}
24+
25+
// returns a value with the high 16 bits set if not valid
26+
// otherwise returns the conversion of the 4 hex digits at src into the bottom
27+
// 16 bits of the 32-bit return register
28+
//
29+
// see
30+
// https://lemire.me/blog/2019/04/17/parsing-short-hexadecimal-strings-efficiently/
31+
static inline uint32_t hex_to_u32_nocheck(
32+
const uint8_t *src) { // strictly speaking, static inline is a C-ism
33+
uint32_t v1 = digit_to_val32[630 + src[0]];
34+
uint32_t v2 = digit_to_val32[420 + src[1]];
35+
uint32_t v3 = digit_to_val32[210 + src[2]];
36+
uint32_t v4 = digit_to_val32[0 + src[3]];
37+
return v1 | v2 | v3 | v4;
38+
}
39+
40+
// given a code point cp, writes to c
41+
// the utf-8 code, outputting the length in
42+
// bytes, if the length is zero, the code point
43+
// is invalid
44+
//
45+
// This can possibly be made faster using pdep
46+
// and clz and table lookups, but JSON documents
47+
// have few escaped code points, and the following
48+
// function looks cheap.
49+
//
50+
// Note: we assume that surrogates are treated separately
51+
//
52+
inline size_t codepoint_to_utf8(uint32_t cp, uint8_t *c) {
53+
if (cp <= 0x7F) {
54+
c[0] = uint8_t(cp);
55+
return 1; // ascii
56+
}
57+
if (cp <= 0x7FF) {
58+
c[0] = uint8_t((cp >> 6) + 192);
59+
c[1] = uint8_t((cp & 63) + 128);
60+
return 2; // universal plane
61+
// Surrogates are treated elsewhere...
62+
//} //else if (0xd800 <= cp && cp <= 0xdfff) {
63+
// return 0; // surrogates // could put assert here
64+
} else if (cp <= 0xFFFF) {
65+
c[0] = uint8_t((cp >> 12) + 224);
66+
c[1] = uint8_t(((cp >> 6) & 63) + 128);
67+
c[2] = uint8_t((cp & 63) + 128);
68+
return 3;
69+
} else if (cp <= 0x10FFFF) { // if you know you have a valid code point, this
70+
// is not needed
71+
c[0] = uint8_t((cp >> 18) + 240);
72+
c[1] = uint8_t(((cp >> 12) & 63) + 128);
73+
c[2] = uint8_t(((cp >> 6) & 63) + 128);
74+
c[3] = uint8_t((cp & 63) + 128);
75+
return 4;
76+
}
77+
// will return 0 when the code point was too large.
78+
return 0; // bad r
79+
}
80+
81+
////
82+
// The following code is used in number parsing. It is not
83+
// properly "char utils" stuff, but we move it here so that
84+
// it does not get copied multiple times in the binaries (once
85+
// per instruction set).
86+
///
87+
88+
constexpr int FASTFLOAT_SMALLEST_POWER = -325;
89+
constexpr int FASTFLOAT_LARGEST_POWER = 308;
90+
91+
struct value128 {
92+
uint64_t low;
93+
uint64_t high;
94+
};
95+
96+
#ifdef SIMDJSON_IS_32BITS // _umul128 for x86, arm
97+
// this is a slow emulation routine for 32-bit
98+
//
99+
static inline uint64_t __emulu(uint32_t x, uint32_t y) {
100+
return x * (uint64_t)y;
101+
}
102+
static inline uint64_t _umul128(uint64_t ab, uint64_t cd, uint64_t *hi) {
103+
uint64_t ad = __emulu((uint32_t)(ab >> 32), (uint32_t)cd);
104+
uint64_t bd = __emulu((uint32_t)ab, (uint32_t)cd);
105+
uint64_t adbc = ad + __emulu((uint32_t)ab, (uint32_t)(cd >> 32));
106+
uint64_t adbc_carry = !!(adbc < ad);
107+
uint64_t lo = bd + (adbc << 32);
108+
*hi = __emulu((uint32_t)(ab >> 32), (uint32_t)(cd >> 32)) + (adbc >> 32) +
109+
(adbc_carry << 32) + !!(lo < bd);
110+
return lo;
111+
}
112+
#endif
113+
114+
really_inline value128 full_multiplication(uint64_t value1, uint64_t value2) {
115+
value128 answer;
116+
#if defined(SIMDJSON_REGULAR_VISUAL_STUDIO) || defined(SIMDJSON_IS_32BITS)
117+
#ifdef _M_ARM64
118+
// ARM64 has native support for 64-bit multiplications, no need to emultate
119+
answer.high = __umulh(value1, value2);
120+
answer.low = value1 * value2;
121+
#else
122+
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
123+
#endif // _M_ARM64
124+
#else // defined(SIMDJSON_REGULAR_VISUAL_STUDIO) || defined(SIMDJSON_IS_32BITS)
125+
__uint128_t r = ((__uint128_t)value1) * value2;
126+
answer.low = uint64_t(r);
127+
answer.high = uint64_t(r >> 64);
128+
#endif
129+
return answer;
130+
}
131+
132+
} // namespace stage2
133+
} // namespace SIMDJSON_IMPLEMENTATION
134+
} // namespace simdjson

src/generic/stage2/numberparsing.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
#include "jsoncharutils.h"
21
#include <cmath>
32
#include <limits>
43

src/generic/stage2/stringparsing.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
// This file contains the common code every implementation uses
22
// It is intended to be included multiple times and compiled multiple times
33

4-
#include "jsoncharutils.h"
5-
64
namespace simdjson {
75
namespace SIMDJSON_IMPLEMENTATION {
86
namespace stage2 {

src/haswell/dom_parser_implementation.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "haswell/begin_implementation.h"
22
#include "haswell/dom_parser_implementation.h"
3+
#include "generic/stage2/jsoncharutils.h"
34

45
//
56
// Stage 1
Lines changed: 3 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
#ifndef SIMDJSON_JSONCHARUTILS_H
2-
#define SIMDJSON_JSONCHARUTILS_H
1+
#ifndef SIMDJSON_JSONCHARUTILS_TABLES_H
2+
#define SIMDJSON_JSONCHARUTILS_TABLES_H
33

44
#include "simdjson.h"
55

@@ -34,12 +34,6 @@ const uint32_t structural_or_whitespace_or_null_negated[256] = {
3434
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3535
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
3636

37-
// return non-zero if not a structural or whitespace char
38-
// zero otherwise
39-
really_inline uint32_t is_not_structural_or_whitespace_or_null(uint8_t c) {
40-
return structural_or_whitespace_or_null_negated[c];
41-
}
42-
4337
const uint32_t structural_or_whitespace_negated[256] = {
4438
1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
4539
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -57,12 +51,6 @@ const uint32_t structural_or_whitespace_negated[256] = {
5751
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5852
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
5953

60-
// return non-zero if not a structural or whitespace char
61-
// zero otherwise
62-
really_inline uint32_t is_not_structural_or_whitespace(uint8_t c) {
63-
return structural_or_whitespace_negated[c];
64-
}
65-
6654
const uint32_t structural_or_whitespace_or_null[256] = {
6755
1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6856
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
@@ -76,10 +64,6 @@ const uint32_t structural_or_whitespace_or_null[256] = {
7664
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7765
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
7866

79-
really_inline uint32_t is_structural_or_whitespace_or_null(uint8_t c) {
80-
return structural_or_whitespace_or_null[c];
81-
}
82-
8367
const uint32_t structural_or_whitespace[256] = {
8468
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8569
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
@@ -93,10 +77,6 @@ const uint32_t structural_or_whitespace[256] = {
9377
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9478
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
9579

96-
really_inline uint32_t is_structural_or_whitespace(uint8_t c) {
97-
return structural_or_whitespace[c];
98-
}
99-
10080
const uint32_t digit_to_val32[886] = {
10181
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
10282
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
@@ -246,62 +226,6 @@ const uint32_t digit_to_val32[886] = {
246226
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
247227
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
248228
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF};
249-
// returns a value with the high 16 bits set if not valid
250-
// otherwise returns the conversion of the 4 hex digits at src into the bottom
251-
// 16 bits of the 32-bit return register
252-
//
253-
// see
254-
// https://lemire.me/blog/2019/04/17/parsing-short-hexadecimal-strings-efficiently/
255-
static inline uint32_t hex_to_u32_nocheck(
256-
const uint8_t *src) { // strictly speaking, static inline is a C-ism
257-
uint32_t v1 = digit_to_val32[630 + src[0]];
258-
uint32_t v2 = digit_to_val32[420 + src[1]];
259-
uint32_t v3 = digit_to_val32[210 + src[2]];
260-
uint32_t v4 = digit_to_val32[0 + src[3]];
261-
return v1 | v2 | v3 | v4;
262-
}
263-
264-
// given a code point cp, writes to c
265-
// the utf-8 code, outputting the length in
266-
// bytes, if the length is zero, the code point
267-
// is invalid
268-
//
269-
// This can possibly be made faster using pdep
270-
// and clz and table lookups, but JSON documents
271-
// have few escaped code points, and the following
272-
// function looks cheap.
273-
//
274-
// Note: we assume that surrogates are treated separately
275-
//
276-
inline size_t codepoint_to_utf8(uint32_t cp, uint8_t *c) {
277-
if (cp <= 0x7F) {
278-
c[0] = uint8_t(cp);
279-
return 1; // ascii
280-
}
281-
if (cp <= 0x7FF) {
282-
c[0] = uint8_t((cp >> 6) + 192);
283-
c[1] = uint8_t((cp & 63) + 128);
284-
return 2; // universal plane
285-
// Surrogates are treated elsewhere...
286-
//} //else if (0xd800 <= cp && cp <= 0xdfff) {
287-
// return 0; // surrogates // could put assert here
288-
} else if (cp <= 0xFFFF) {
289-
c[0] = uint8_t((cp >> 12) + 224);
290-
c[1] = uint8_t(((cp >> 6) & 63) + 128);
291-
c[2] = uint8_t((cp & 63) + 128);
292-
return 3;
293-
} else if (cp <= 0x10FFFF) { // if you know you have a valid code point, this
294-
// is not needed
295-
c[0] = uint8_t((cp >> 18) + 240);
296-
c[1] = uint8_t(((cp >> 12) & 63) + 128);
297-
c[2] = uint8_t(((cp >> 6) & 63) + 128);
298-
c[3] = uint8_t((cp & 63) + 128);
299-
return 4;
300-
}
301-
// will return 0 when the code point was too large.
302-
return 0; // bad r
303-
}
304-
305229
////
306230
// The following code is used in number parsing. It is not
307231
// properly "char utils" stuff, but we move it here so that
@@ -317,42 +241,6 @@ struct value128 {
317241
uint64_t high;
318242
};
319243

320-
#ifdef SIMDJSON_IS_32BITS // _umul128 for x86, arm
321-
// this is a slow emulation routine for 32-bit
322-
//
323-
static inline uint64_t __emulu(uint32_t x, uint32_t y) {
324-
return x * (uint64_t)y;
325-
}
326-
static inline uint64_t _umul128(uint64_t ab, uint64_t cd, uint64_t *hi) {
327-
uint64_t ad = __emulu((uint32_t)(ab >> 32), (uint32_t)cd);
328-
uint64_t bd = __emulu((uint32_t)ab, (uint32_t)cd);
329-
uint64_t adbc = ad + __emulu((uint32_t)ab, (uint32_t)(cd >> 32));
330-
uint64_t adbc_carry = !!(adbc < ad);
331-
uint64_t lo = bd + (adbc << 32);
332-
*hi = __emulu((uint32_t)(ab >> 32), (uint32_t)(cd >> 32)) + (adbc >> 32) +
333-
(adbc_carry << 32) + !!(lo < bd);
334-
return lo;
335-
}
336-
#endif
337-
338-
really_inline value128 full_multiplication(uint64_t value1, uint64_t value2) {
339-
value128 answer;
340-
#if defined(SIMDJSON_REGULAR_VISUAL_STUDIO) || defined(SIMDJSON_IS_32BITS)
341-
#ifdef _M_ARM64
342-
// ARM64 has native support for 64-bit multiplications, no need to emultate
343-
answer.high = __umulh(value1, value2);
344-
answer.low = value1 * value2;
345-
#else
346-
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
347-
#endif // _M_ARM64
348-
#else // defined(SIMDJSON_REGULAR_VISUAL_STUDIO) || defined(SIMDJSON_IS_32BITS)
349-
__uint128_t r = ((__uint128_t)value1) * value2;
350-
answer.low = uint64_t(r);
351-
answer.high = uint64_t(r >> 64);
352-
#endif
353-
return answer;
354-
}
355-
356244
// Precomputed powers of ten from 10^0 to 10^22. These
357245
// can be represented exactly using the double type.
358246
static const double power_of_ten[] = {
@@ -1333,4 +1221,4 @@ const uint64_t mantissa_128[] = {
13331221

13341222
} // namespace simdjson
13351223

1336-
#endif // SIMDJSON_JSONCHARUTILS_H
1224+
#endif // SIMDJSON_JSONCHARUTILS_TABLES_H

src/simdjson.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ SIMDJSON_DISABLE_UNDESIRED_WARNINGS
99
// Anything in the top level directory MUST be included outside of the #if statements
1010
// below, or amalgamation will screw them up!
1111
#include "isadetection.h"
12-
#include "jsoncharutils.h"
12+
#include "jsoncharutils_tables.h"
1313
#include "simdprune_tables.h"
1414

1515
#if SIMDJSON_IMPLEMENTATION_ARM64

src/westmere/dom_parser_implementation.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#include "westmere/begin_implementation.h"
2+
#include "westmere/dom_parser_implementation.h"
3+
#include "generic/stage2/jsoncharutils.h"
24

35
//
46
// Stage 1

0 commit comments

Comments
 (0)