/src/build-dir/_deps/simdjson-src/src/implementation.cpp
Line | Count | Source |
1 | | #ifndef SIMDJSON_SRC_IMPLEMENTATION_CPP |
2 | | #define SIMDJSON_SRC_IMPLEMENTATION_CPP |
3 | | |
4 | | #include <base.h> |
5 | | #include <simdjson/generic/dependencies.h> |
6 | | #include <simdjson/implementation.h> |
7 | | #include <internal/isadetection.h> |
8 | | |
9 | | #include <initializer_list> |
10 | | #include <type_traits> |
11 | | |
12 | | namespace simdjson { |
13 | | |
14 | 0 | bool implementation::supported_by_runtime_system() const { |
15 | 0 | uint32_t required_instruction_sets = this->required_instruction_sets(); |
16 | 0 | uint32_t supported_instruction_sets = internal::detect_supported_architectures(); |
17 | 0 | return ((supported_instruction_sets & required_instruction_sets) == required_instruction_sets); |
18 | 0 | } |
19 | | |
20 | | } // namespace simdjson |
21 | | |
22 | | #define SIMDJSON_CONDITIONAL_INCLUDE |
23 | | |
24 | | #if SIMDJSON_IMPLEMENTATION_ARM64 |
25 | | #include <simdjson/arm64/implementation.h> |
26 | | namespace simdjson { |
27 | | namespace internal { |
28 | | static const arm64::implementation* get_arm64_singleton() { |
29 | | static const arm64::implementation arm64_singleton{}; |
30 | | return &arm64_singleton; |
31 | | } |
32 | | } // namespace internal |
33 | | } // namespace simdjson |
34 | | #endif // SIMDJSON_IMPLEMENTATION_ARM64 |
35 | | |
36 | | #if SIMDJSON_IMPLEMENTATION_FALLBACK |
37 | | #include <simdjson/fallback/implementation.h> |
38 | | namespace simdjson { |
39 | | namespace internal { |
40 | 0 | static const fallback::implementation* get_fallback_singleton() { |
41 | 0 | static const fallback::implementation fallback_singleton{}; |
42 | 0 | return &fallback_singleton; |
43 | 0 | } |
44 | | } // namespace internal |
45 | | } // namespace simdjson |
46 | | #endif // SIMDJSON_IMPLEMENTATION_FALLBACK |
47 | | |
48 | | |
49 | | #if SIMDJSON_IMPLEMENTATION_HASWELL |
50 | | #include <simdjson/haswell/implementation.h> |
51 | | namespace simdjson { |
52 | | namespace internal { |
53 | 0 | static const haswell::implementation* get_haswell_singleton() { |
54 | 0 | static const haswell::implementation haswell_singleton{}; |
55 | 0 | return &haswell_singleton; |
56 | 0 | } |
57 | | } // namespace internal |
58 | | } // namespace simdjson |
59 | | #endif |
60 | | |
61 | | #if SIMDJSON_IMPLEMENTATION_ICELAKE |
62 | | #include <simdjson/icelake/implementation.h> |
63 | | namespace simdjson { |
64 | | namespace internal { |
65 | 0 | static const icelake::implementation* get_icelake_singleton() { |
66 | 0 | static const icelake::implementation icelake_singleton{}; |
67 | 0 | return &icelake_singleton; |
68 | 0 | } |
69 | | } // namespace internal |
70 | | } // namespace simdjson |
71 | | #endif |
72 | | |
73 | | #if SIMDJSON_IMPLEMENTATION_PPC64 |
74 | | #include <simdjson/ppc64/implementation.h> |
75 | | namespace simdjson { |
76 | | namespace internal { |
77 | | static const ppc64::implementation* get_ppc64_singleton() { |
78 | | static const ppc64::implementation ppc64_singleton{}; |
79 | | return &ppc64_singleton; |
80 | | } |
81 | | } // namespace internal |
82 | | } // namespace simdjson |
83 | | #endif // SIMDJSON_IMPLEMENTATION_PPC64 |
84 | | |
85 | | #if SIMDJSON_IMPLEMENTATION_WESTMERE |
86 | | #include <simdjson/westmere/implementation.h> |
87 | | namespace simdjson { |
88 | | namespace internal { |
89 | 0 | static const simdjson::westmere::implementation* get_westmere_singleton() { |
90 | 0 | static const simdjson::westmere::implementation westmere_singleton{}; |
91 | 0 | return &westmere_singleton; |
92 | 0 | } |
93 | | } // namespace internal |
94 | | } // namespace simdjson |
95 | | #endif // SIMDJSON_IMPLEMENTATION_WESTMERE |
96 | | |
97 | | #if SIMDJSON_IMPLEMENTATION_LASX |
98 | | #include <simdjson/lasx/implementation.h> |
99 | | namespace simdjson { |
100 | | namespace internal { |
101 | | static const simdjson::lasx::implementation* get_lasx_singleton() { |
102 | | static const simdjson::lasx::implementation lasx_singleton{}; |
103 | | return &lasx_singleton; |
104 | | } |
105 | | } // namespace internal |
106 | | } // namespace simdjson |
107 | | #endif // SIMDJSON_IMPLEMENTATION_LASX |
108 | | |
109 | | #if SIMDJSON_IMPLEMENTATION_LSX |
110 | | #include <simdjson/lsx/implementation.h> |
111 | | namespace simdjson { |
112 | | namespace internal { |
113 | | static const simdjson::lsx::implementation* get_lsx_singleton() { |
114 | | static const simdjson::lsx::implementation lsx_singleton{}; |
115 | | return &lsx_singleton; |
116 | | } |
117 | | } // namespace internal |
118 | | } // namespace simdjson |
119 | | #endif // SIMDJSON_IMPLEMENTATION_LSX |
120 | | |
121 | | #if SIMDJSON_IMPLEMENTATION_RVV_VLS |
122 | | #include <simdjson/rvv-vls/implementation.h> |
123 | | namespace simdjson { |
124 | | namespace internal { |
125 | | static const simdjson::rvv_vls::implementation* get_rvv_vls_singleton() { |
126 | | static const simdjson::rvv_vls::implementation rvv_vls_singleton{}; |
127 | | return &rvv_vls_singleton; |
128 | | } |
129 | | } // namespace internal |
130 | | } // namespace simdjson |
131 | | #endif // SIMDJSON_IMPLEMENTATION_RVV_VLS |
132 | | |
133 | | #undef SIMDJSON_CONDITIONAL_INCLUDE |
134 | | |
135 | | namespace simdjson { |
136 | | namespace internal { |
137 | | |
138 | | // When there is a single implementation, we should not pay a price |
139 | | // for dispatching to the best implementation. We should just use the |
140 | | // one we have. This is a compile-time check. |
141 | | #define SIMDJSON_SINGLE_IMPLEMENTATION (SIMDJSON_IMPLEMENTATION_ICELAKE \ |
142 | | + SIMDJSON_IMPLEMENTATION_HASWELL + SIMDJSON_IMPLEMENTATION_WESTMERE \ |
143 | | + SIMDJSON_IMPLEMENTATION_ARM64 + SIMDJSON_IMPLEMENTATION_PPC64 \ |
144 | | + SIMDJSON_IMPLEMENTATION_LSX + SIMDJSON_IMPLEMENTATION_LASX \ |
145 | | + SIMDJSON_IMPLEMENTATION_RVV_VLS + SIMDJSON_IMPLEMENTATION_FALLBACK == 1) |
146 | | |
147 | | #if SIMDJSON_SINGLE_IMPLEMENTATION |
148 | | simdjson_really_inline static const implementation* get_single_implementation() { |
149 | | return |
150 | | #if SIMDJSON_IMPLEMENTATION_ICELAKE |
151 | | get_icelake_singleton(); |
152 | | #endif |
153 | | #if SIMDJSON_IMPLEMENTATION_HASWELL |
154 | | get_haswell_singleton(); |
155 | | #endif |
156 | | #if SIMDJSON_IMPLEMENTATION_WESTMERE |
157 | | get_westmere_singleton(); |
158 | | #endif |
159 | | #if SIMDJSON_IMPLEMENTATION_ARM64 |
160 | | get_arm64_singleton(); |
161 | | #endif |
162 | | #if SIMDJSON_IMPLEMENTATION_PPC64 |
163 | | get_ppc64_singleton(); |
164 | | #endif |
165 | | #if SIMDJSON_IMPLEMENTATION_LSX |
166 | | get_lsx_singleton(); |
167 | | #endif |
168 | | #if SIMDJSON_IMPLEMENTATION_LASX |
169 | | get_lasx_singleton(); |
170 | | #endif |
171 | | #if SIMDJSON_IMPLEMENTATION_RVV_VLS |
172 | | get_rvv_vls_singleton(); |
173 | | #endif |
174 | | #if SIMDJSON_IMPLEMENTATION_FALLBACK |
175 | | get_fallback_singleton(); |
176 | | #endif |
177 | | } |
178 | | #endif |
179 | | |
180 | | // Static array of known implementations. We're hoping these get baked into the executable |
181 | | // without requiring a static initializer. |
182 | | |
183 | | /** |
184 | | * @private Detects best supported implementation on first use, and sets it |
185 | | */ |
186 | | class detect_best_supported_implementation_on_first_use final : public implementation { |
187 | | public: |
188 | 0 | std::string name() const noexcept final { return set_best()->name(); } |
189 | 0 | std::string description() const noexcept final { return set_best()->description(); } |
190 | 0 | uint32_t required_instruction_sets() const noexcept final { return set_best()->required_instruction_sets(); } |
191 | | simdjson_warn_unused error_code create_dom_parser_implementation( |
192 | | size_t capacity, |
193 | | size_t max_length, |
194 | | std::unique_ptr<internal::dom_parser_implementation>& dst |
195 | 0 | ) const noexcept final { |
196 | 0 | return set_best()->create_dom_parser_implementation(capacity, max_length, dst); |
197 | 0 | } |
198 | 0 | simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final { |
199 | 0 | return set_best()->minify(buf, len, dst, dst_len); |
200 | 0 | } |
201 | 0 | simdjson_warn_unused bool validate_utf8(const char * buf, size_t len) const noexcept final override { |
202 | 0 | return set_best()->validate_utf8(buf, len); |
203 | 0 | } |
204 | 0 | simdjson_inline detect_best_supported_implementation_on_first_use() noexcept : implementation("best_supported_detector", "Detects the best supported implementation and sets it", 0) {} |
205 | | private: |
206 | | const implementation *set_best() const noexcept; |
207 | | }; |
208 | | |
209 | | static_assert(std::is_trivially_destructible<detect_best_supported_implementation_on_first_use>::value, "detect_best_supported_implementation_on_first_use should be trivially destructible"); |
210 | | |
211 | 0 | static const std::initializer_list<const implementation *>& get_available_implementation_pointers() { |
212 | 0 | static const std::initializer_list<const implementation *> available_implementation_pointers { |
213 | 0 | #if SIMDJSON_IMPLEMENTATION_ICELAKE |
214 | 0 | get_icelake_singleton(), |
215 | 0 | #endif |
216 | 0 | #if SIMDJSON_IMPLEMENTATION_HASWELL |
217 | 0 | get_haswell_singleton(), |
218 | 0 | #endif |
219 | 0 | #if SIMDJSON_IMPLEMENTATION_WESTMERE |
220 | 0 | get_westmere_singleton(), |
221 | 0 | #endif |
222 | | #if SIMDJSON_IMPLEMENTATION_ARM64 |
223 | | get_arm64_singleton(), |
224 | | #endif |
225 | | #if SIMDJSON_IMPLEMENTATION_PPC64 |
226 | | get_ppc64_singleton(), |
227 | | #endif |
228 | | #if SIMDJSON_IMPLEMENTATION_LASX |
229 | | get_lasx_singleton(), |
230 | | #endif |
231 | | #if SIMDJSON_IMPLEMENTATION_LSX |
232 | | get_lsx_singleton(), |
233 | | #endif |
234 | | #if SIMDJSON_IMPLEMENTATION_RVV_VLS |
235 | | get_rvv_vls_singleton(), |
236 | | #endif |
237 | 0 | #if SIMDJSON_IMPLEMENTATION_FALLBACK |
238 | 0 | get_fallback_singleton(), |
239 | 0 | #endif |
240 | 0 | }; // available_implementation_pointers |
241 | 0 | return available_implementation_pointers; |
242 | 0 | } |
243 | | |
244 | | // So we can return UNSUPPORTED_ARCHITECTURE from the parser when there is no support |
245 | | class unsupported_implementation final : public implementation { |
246 | | public: |
247 | | simdjson_warn_unused error_code create_dom_parser_implementation( |
248 | | size_t, |
249 | | size_t, |
250 | | std::unique_ptr<internal::dom_parser_implementation>& |
251 | 0 | ) const noexcept final { |
252 | 0 | return UNSUPPORTED_ARCHITECTURE; |
253 | 0 | } |
254 | 0 | simdjson_warn_unused error_code minify(const uint8_t *, size_t, uint8_t *, size_t &) const noexcept final override { |
255 | 0 | return UNSUPPORTED_ARCHITECTURE; |
256 | 0 | } |
257 | 0 | simdjson_warn_unused bool validate_utf8(const char *, size_t) const noexcept final override { |
258 | 0 | return false; // Just refuse to validate. Given that we have a fallback implementation |
259 | | // it seems unlikely that unsupported_implementation will ever be used. If it is used, |
260 | | // then it will flag all strings as invalid. The alternative is to return an error_code |
261 | | // from which the user has to figure out whether the string is valid UTF-8... which seems |
262 | | // like a lot of work just to handle the very unlikely case that we have an unsupported |
263 | | // implementation. And, when it does happen (that we have an unsupported implementation), |
264 | | // what are the chances that the programmer has a fallback? Given that *we* provide the |
265 | | // fallback, it implies that the programmer would need a fallback for our fallback. |
266 | 0 | } |
267 | 0 | unsupported_implementation() : implementation("unsupported", "Unsupported CPU (no detected SIMD instructions)", 0) {} |
268 | | }; |
269 | | |
270 | | static_assert(std::is_trivially_destructible<unsupported_implementation>::value, "unsupported_singleton should be trivially destructible"); |
271 | | |
272 | 0 | const unsupported_implementation* get_unsupported_singleton() { |
273 | 0 | static const unsupported_implementation unsupported_singleton{}; |
274 | 0 | return &unsupported_singleton; |
275 | 0 | } |
276 | | |
277 | 0 | size_t available_implementation_list::size() const noexcept { |
278 | 0 | return internal::get_available_implementation_pointers().size(); |
279 | 0 | } |
280 | 0 | const implementation * const *available_implementation_list::begin() const noexcept { |
281 | 0 | return internal::get_available_implementation_pointers().begin(); |
282 | 0 | } |
283 | 0 | const implementation * const *available_implementation_list::end() const noexcept { |
284 | 0 | return internal::get_available_implementation_pointers().end(); |
285 | 0 | } |
286 | 0 | const implementation *available_implementation_list::detect_best_supported() const noexcept { |
287 | | // They are prelisted in priority order, so we just go down the list |
288 | 0 | uint32_t supported_instruction_sets = internal::detect_supported_architectures(); |
289 | 0 | for (const implementation *impl : internal::get_available_implementation_pointers()) { |
290 | 0 | uint32_t required_instruction_sets = impl->required_instruction_sets(); |
291 | 0 | if ((supported_instruction_sets & required_instruction_sets) == required_instruction_sets) { return impl; } |
292 | 0 | } |
293 | 0 | return get_unsupported_singleton(); // this should never happen? |
294 | 0 | } |
295 | | |
296 | 0 | const implementation *detect_best_supported_implementation_on_first_use::set_best() const noexcept { |
297 | 0 | SIMDJSON_PUSH_DISABLE_WARNINGS |
298 | | SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe |
299 | 0 | char *force_implementation_name = getenv("SIMDJSON_FORCE_IMPLEMENTATION"); |
300 | 0 | SIMDJSON_POP_DISABLE_WARNINGS |
301 | |
|
302 | 0 | if (force_implementation_name) { |
303 | 0 | auto force_implementation = get_available_implementations()[force_implementation_name]; |
304 | 0 | if (force_implementation) { |
305 | 0 | return get_active_implementation() = force_implementation; |
306 | 0 | } else { |
307 | | // Note: abort() and stderr usage within the library is forbidden. |
308 | 0 | return get_active_implementation() = get_unsupported_singleton(); |
309 | 0 | } |
310 | 0 | } |
311 | 0 | return get_active_implementation() = get_available_implementations().detect_best_supported(); |
312 | 0 | } |
313 | | |
314 | | } // namespace internal |
315 | | |
316 | 0 | SIMDJSON_DLLIMPORTEXPORT const internal::available_implementation_list& get_available_implementations() { |
317 | 0 | static const internal::available_implementation_list available_implementations{}; |
318 | 0 | return available_implementations; |
319 | 0 | } |
320 | | |
321 | 0 | SIMDJSON_DLLIMPORTEXPORT internal::atomic_ptr<const implementation>& get_active_implementation() { |
322 | | #if SIMDJSON_SINGLE_IMPLEMENTATION |
323 | | // We immediately select the only implementation we have, skipping the |
324 | | // detect_best_supported_implementation_on_first_use_singleton. |
325 | | static internal::atomic_ptr<const implementation> active_implementation{internal::get_single_implementation()}; |
326 | | return active_implementation; |
327 | | #else |
328 | 0 | static const internal::detect_best_supported_implementation_on_first_use detect_best_supported_implementation_on_first_use_singleton; |
329 | 0 | static internal::atomic_ptr<const implementation> active_implementation{&detect_best_supported_implementation_on_first_use_singleton}; |
330 | 0 | return active_implementation; |
331 | 0 | #endif |
332 | 0 | } |
333 | | |
334 | 0 | simdjson_warn_unused error_code minify(const char *buf, size_t len, char *dst, size_t &dst_len) noexcept { |
335 | 0 | return get_active_implementation()->minify(reinterpret_cast<const uint8_t *>(buf), len, reinterpret_cast<uint8_t *>(dst), dst_len); |
336 | 0 | } |
337 | 0 | simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) noexcept { |
338 | 0 | return get_active_implementation()->validate_utf8(buf, len); |
339 | 0 | } |
340 | 0 | const implementation * builtin_implementation() { |
341 | 0 | static const implementation * builtin_impl = get_available_implementations()[SIMDJSON_STRINGIFY(SIMDJSON_BUILTIN_IMPLEMENTATION)]; |
342 | | assert(builtin_impl); |
343 | 0 | return builtin_impl; |
344 | 0 | } |
345 | | |
346 | | } // namespace simdjson |
347 | | |
348 | | #endif // SIMDJSON_SRC_IMPLEMENTATION_CPP |