simdjson 5.0.2
Ridiculously Fast JSON
Loading...
Searching...
No Matches
atomparsing.h
1#ifndef SIMDJSON_GENERIC_ATOMPARSING_H
2
3#ifndef SIMDJSON_CONDITIONAL_INCLUDE
4#define SIMDJSON_GENERIC_ATOMPARSING_H
5#include "simdjson/generic/base.h"
6#include "simdjson/generic/jsoncharutils.h"
7#endif // SIMDJSON_CONDITIONAL_INCLUDE
8
9#include <cstring>
10
11namespace simdjson {
12namespace SIMDJSON_IMPLEMENTATION {
13namespace {
15namespace atomparsing {
16
17// The string_to_uint32 is exclusively used to map literal strings to 32-bit values.
18// We use memcpy instead of a pointer cast to avoid undefined behaviors since we cannot
19// be certain that the character pointer will be properly aligned.
20// You might think that using memcpy makes this function expensive, but you'd be wrong.
21// All decent optimizing compilers (GCC, clang, Visual Studio) will compile string_to_uint32("false");
22// to the compile-time constant 1936482662.
23simdjson_inline uint32_t string_to_uint32(const char* str) { uint32_t val; std::memcpy(&val, str, sizeof(uint32_t)); return val; }
24
25// Acts on the same principle as string_to_uint32, but on an 8-byte block of memory
26simdjson_inline uint64_t string_to_uint64(const char* str) { uint64_t val; std::memcpy(&val, str, sizeof(uint64_t)); return val; }
27
28
29// Again in str4ncmp we use a memcpy to avoid undefined behavior. The memcpy may appear expensive.
30// Yet all decent optimizing compilers will compile memcpy to a single instruction, just about.
31simdjson_warn_unused
32simdjson_inline uint32_t str4ncmp(const uint8_t *src, const char* atom) {
33 uint32_t srcval; // we want to avoid unaligned 32-bit loads (undefined in C/C++)
34 static_assert(sizeof(uint32_t) <= SIMDJSON_PADDING, "SIMDJSON_PADDING must be larger than 4 bytes");
35 std::memcpy(&srcval, src, sizeof(uint32_t));
36 return srcval ^ string_to_uint32(atom);
37}
38
39// Checks that the first 8 characters of the input string match the given atom in a case-insensitive manner.
40//
41// 'atom' must consist of only lowercase letters.
42simdjson_warn_unused
43simdjson_inline uint64_t str8ncmp_case_insensitive(const uint8_t *src, const char* atom) {
44 uint64_t srcval; // we want to avoid unaligned 32-bit loads (undefined in C/C++)
45 static_assert(sizeof(uint64_t) <= SIMDJSON_PADDING, "SIMDJSON_PADDING must be larger than 8 bytes");
46 std::memcpy(&srcval, src, sizeof(uint64_t));
47
48 return (srcval | 0x2020202020202020ull) ^ string_to_uint64(atom);
49}
50
51// Checks that the first 3 characters of 'src' match 'atom' in a case-insensitive way.
52//
53// 'atom' must consist of only lowercase letters.
54simdjson_warn_unused
55simdjson_inline uint32_t str3ncmp_case_insensitive(const uint8_t *src, const char* atom) {
56 return ((src[0] | 0x20) ^ atom[0]) //
57 | ((src[1] | 0x20) ^ atom[1]) //
58 | ((src[2] | 0x20) ^ atom[2]);
59}
60
61simdjson_warn_unused
62simdjson_inline bool is_valid_true_atom(const uint8_t *src) {
63 return (str4ncmp(src, "true") | jsoncharutils::is_not_structural_or_whitespace(src[4])) == 0;
64}
65
66simdjson_warn_unused
67simdjson_inline bool is_valid_true_atom(const uint8_t *src, size_t len) {
68 if (len > 4) { return is_valid_true_atom(src); }
69 else if (len == 4) { return !str4ncmp(src, "true"); }
70 else { return false; }
71}
72
73simdjson_warn_unused
74simdjson_inline bool is_valid_false_atom(const uint8_t *src) {
75 return (str4ncmp(src+1, "alse") | jsoncharutils::is_not_structural_or_whitespace(src[5])) == 0;
76}
77
78simdjson_warn_unused
79simdjson_inline bool is_valid_false_atom(const uint8_t *src, size_t len) {
80 if (len > 5) { return is_valid_false_atom(src); }
81 else if (len == 5) { return !str4ncmp(src+1, "alse"); }
82 else { return false; }
83}
84
85simdjson_warn_unused
86simdjson_inline bool is_valid_null_atom(const uint8_t *src) {
87 return (str4ncmp(src, "null") | jsoncharutils::is_not_structural_or_whitespace(src[4])) == 0;
88}
89
90simdjson_warn_unused
91simdjson_inline bool is_valid_null_atom(const uint8_t *src, size_t len) {
92 if (len > 4) { return is_valid_null_atom(src); }
93 else if (len == 4) { return !str4ncmp(src, "null"); }
94 else { return false; }
95}
96
97#if SIMDJSON_ENABLE_NAN_INF
98// "nan" is 3 bytes; we check characters and then verify the next
99// character is structural or whitespace. We accept both "nan" and "NaN".
100simdjson_warn_unused
101simdjson_inline bool is_valid_nan_atom(const uint8_t *src) {
102 return (str3ncmp_case_insensitive(src, "nan")
103 | jsoncharutils::is_not_structural_or_whitespace(src[3])) == 0;
104}
105
106// checks that the next four characters of a string are 'nan"', where the 'nan'
107// is checked in a case-insensitive way.
108simdjson_warn_unused
109simdjson_inline bool is_valid_nan_in_string(const uint8_t *src) {
110 return (str3ncmp_case_insensitive(src, "nan") | (src[3] ^ '"')) == 0;
111}
112
113simdjson_warn_unused
114simdjson_inline bool is_valid_nan_atom(const uint8_t *src, size_t len) {
115 if (len > 3) { return is_valid_nan_atom(src); }
116 if (len == 3) { return str3ncmp_case_insensitive(src, "nan") == 0; }
117 return false;
118}
119
120// This function will accept any case-insensitive 3-character spelling of
121// infinity: 'inf', 'INF', and 'Inf' are all accepted.
122//
123// Any capitalization of 'infinity' is also accepted.
124simdjson_warn_unused
125simdjson_inline bool is_valid_inf_atom(const uint8_t *src) {
126 bool is_short_inf = (str3ncmp_case_insensitive(src, "inf")
127 | jsoncharutils::is_not_structural_or_whitespace(src[3])) == 0;
128 if(is_short_inf) return true;
129
130 // Check for 'infinity' (any capitalization)
131 return (str8ncmp_case_insensitive(src, "infinity") | jsoncharutils::is_not_structural_or_whitespace(src[8])) == 0;
132}
133
134simdjson_warn_unused
135simdjson_inline bool is_valid_inf_in_string(const uint8_t *src) {
136 bool is_short_inf = (str3ncmp_case_insensitive(src, "inf") | (src[3] ^ '"')) == 0;
137 if(is_short_inf) return true;
138
139 return (str8ncmp_case_insensitive(src, "infinity") | (src[8] ^ '"')) == 0;
140}
141
142
143// This function will accept any case-insensitive 3-character spelling of
144// infinity: 'inf', 'INF', and 'Inf' are all accepted.
145//
146// Any capitalization of 'infinity' is also accepted.
147simdjson_warn_unused
148simdjson_inline bool is_valid_inf_atom(const uint8_t *src, size_t len) {
149 if (len > 8) { return is_valid_inf_atom(src); }
150 if (len == 8 && str8ncmp_case_insensitive(src, "infinity") == 0) {
151 return true;
152 }
153 if (len > 3) {
154 return (str3ncmp_case_insensitive(src, "inf")
155 | jsoncharutils::is_not_structural_or_whitespace(src[3])) == 0;
156 }
157 if (len == 3) { return str3ncmp_case_insensitive(src, "inf") == 0; }
158 return false;
159}
160#endif // SIMDJSON_ENABLE_NAN_INF
161
162} // namespace atomparsing
163} // unnamed namespace
164} // namespace SIMDJSON_IMPLEMENTATION
165} // namespace simdjson
166
167#endif // SIMDJSON_GENERIC_ATOMPARSING_H
The top level simdjson namespace, containing everything the library provides.
Definition base.h:8
constexpr size_t SIMDJSON_PADDING
The amount of padding needed in a buffer to parse JSON.
Definition base.h:42