1 | #include "simdjson/jsonparser.h" |
2 | #include "simdjson/isadetection.h" |
3 | #include "simdjson/portability.h" |
4 | #include "simdjson/simdjson.h" |
5 | #include <atomic> |
6 | |
7 | namespace simdjson { |
8 | |
9 | // The function that users are expected to call is json_parse. |
10 | // We have more than one such function because we want to support several |
11 | // instruction sets. |
12 | |
13 | // function pointer type for json_parse |
14 | using json_parse_functype = int(const uint8_t *buf, size_t len, ParsedJson &pj, |
15 | bool realloc); |
16 | |
17 | // Pointer that holds the json_parse implementation corresponding to the |
18 | // available SIMD instruction set |
19 | extern std::atomic<json_parse_functype *> json_parse_ptr; |
20 | |
21 | int json_parse(const uint8_t *buf, size_t len, ParsedJson &pj, |
22 | bool realloc) { |
23 | return json_parse_ptr.load(std::memory_order_relaxed)(buf, len, pj, realloc); |
24 | } |
25 | |
26 | int json_parse(const char *buf, size_t len, ParsedJson &pj, |
27 | bool realloc) { |
28 | return json_parse_ptr.load(std::memory_order_relaxed)(reinterpret_cast<const uint8_t *>(buf), len, pj, |
29 | realloc); |
30 | } |
31 | |
32 | Architecture find_best_supported_architecture() { |
33 | constexpr uint32_t haswell_flags = |
34 | instruction_set::AVX2 | instruction_set::PCLMULQDQ | |
35 | instruction_set::BMI1 | instruction_set::BMI2; |
36 | constexpr uint32_t westmere_flags = |
37 | instruction_set::SSE42 | instruction_set::PCLMULQDQ; |
38 | |
39 | uint32_t supports = detect_supported_architectures(); |
40 | // Order from best to worst (within architecture) |
41 | if ((haswell_flags & supports) == haswell_flags) |
42 | return Architecture::HASWELL; |
43 | if ((westmere_flags & supports) == westmere_flags) |
44 | return Architecture::WESTMERE; |
45 | if (supports & instruction_set::NEON) |
46 | return Architecture::ARM64; |
47 | |
48 | return Architecture::UNSUPPORTED; |
49 | } |
50 | |
51 | Architecture parse_architecture(char *architecture) { |
52 | if (!strcmp(architecture, "HASWELL" )) { return Architecture::HASWELL; } |
53 | if (!strcmp(architecture, "WESTMERE" )) { return Architecture::WESTMERE; } |
54 | if (!strcmp(architecture, "ARM64" )) { return Architecture::ARM64; } |
55 | return Architecture::UNSUPPORTED; |
56 | } |
57 | |
58 | // Responsible to select the best json_parse implementation |
59 | int json_parse_dispatch(const uint8_t *buf, size_t len, ParsedJson &pj, |
60 | bool realloc) { |
61 | Architecture best_implementation = find_best_supported_architecture(); |
62 | // Selecting the best implementation |
63 | switch (best_implementation) { |
64 | #ifdef IS_X86_64 |
65 | case Architecture::HASWELL: |
66 | json_parse_ptr.store(&json_parse_implementation<Architecture::HASWELL>, std::memory_order_relaxed); |
67 | break; |
68 | case Architecture::WESTMERE: |
69 | json_parse_ptr.store(&json_parse_implementation<Architecture::WESTMERE>, std::memory_order_relaxed); |
70 | break; |
71 | #endif |
72 | #ifdef IS_ARM64 |
73 | case Architecture::ARM64: |
74 | json_parse_ptr.store(&json_parse_implementation<Architecture::ARM64>, std::memory_order_relaxed); |
75 | break; |
76 | #endif |
77 | default: |
78 | std::cerr << "The processor is not supported by simdjson." << std::endl; |
79 | return simdjson::UNEXPECTED_ERROR; |
80 | } |
81 | |
82 | return json_parse_ptr.load(std::memory_order_relaxed)(buf, len, pj, realloc); |
83 | } |
84 | |
85 | std::atomic<json_parse_functype *> json_parse_ptr{&json_parse_dispatch}; |
86 | |
87 | WARN_UNUSED |
88 | ParsedJson build_parsed_json(const uint8_t *buf, size_t len, |
89 | bool realloc) { |
90 | ParsedJson pj; |
91 | bool ok = pj.allocate_capacity(len); |
92 | if (ok) { |
93 | json_parse(buf, len, pj, realloc); |
94 | } else { |
95 | std::cerr << "failure during memory allocation " << std::endl; |
96 | } |
97 | return pj; |
98 | } |
99 | } // namespace simdjson |
100 | |