Compare commits

...

164 Commits

Author SHA1 Message Date
Daniel Lemire e510ed2774 Release candidate (3.7.0) (#2136)
* Release candidate (3.7.0)

* some extra comments.
2024-02-23 16:50:55 -05:00
Dirk Stolle dabac13dde Add missing word in documentation (#2133) 2024-02-18 11:50:12 -05:00
Daniel Lemire aef7111c05 Documenting Unicode support in JSONPath and JSON Pointer (#2132)
* Documenting our support of JSON Path and JSON Pointer vs. Unicode characters

* using more standard terminology (nitpicking)

* specifying UTF-8 encoding

* allow char8_t when compiling as C++20

* casting

* minor doc corrections
2024-02-15 20:28:38 -05:00
Daniel Lemire 0c08894a54 adopting string literals (#2128)
* adopting string literals

* String suffixes are C++14
2024-02-15 10:40:11 -05:00
Daniel Lemire 2fe3a1467d This PR adds a convenience method (is_string) as well as a new method (#2131)
key_raw_json_token() to get the raw key token.
2024-02-15 10:39:30 -05:00
Daniel Lemire 167a46a0e7 adding remark 2024-02-15 09:56:05 -05:00
Francisco Geiman Thiesen 2b532489cc Adding on-demand support for a subset of json path. (#2127)
* First implementation of the conversion logic.

- Not yet tested
- Not yet compiled
- Not yet used in ondemand array/object/etc...

* Adding at_path to ondemand arrays

* Adding at_path to array, document and value.

* Adding at_path to ondemand object as well.

Pending:
- Building
- Adding tests for each of the on-demand classes usage of at_path
- Properly documenting the subset of json path that is currently supported.

* Adding a simple json_path test to on_demand

* Still trying to compile the ondemand_readme_examples test with the at_path() call

* Fixing linking issues with array::at_path

* Fixing issues with the path -> pointer conversion and removing comments

* Adding a clone of json_pointer to test json_path extensively

* Adding ondemand_json_path_tests (all tests passing)

* Adding documentation for at_path()

* Removing some newlines

* Removing simdjson_result from the return type of the string conversion function. Now json_path_to_pointer_conversion returns a std::string.

* Fixing typo

* Making string concatenation explicit to avoid ubuntu gcc12 issue with -O3 flag.

* Addressing latest reviews

* Addressing latest reviews
2024-02-15 09:47:25 -05:00
Daniel Lemire 85163df88c Update ondemand_design.md 2024-02-14 23:36:25 -05:00
Daniel Lemire 6a5be0f0db Create SECURITY.md 2024-02-09 17:16:54 -05:00
Daniel Lemire 710a3c7241 Update implementation-selection.md 2024-02-09 11:46:22 -05:00
Daniel Lemire c93e02e172 Update implementation-selection.md 2024-02-09 11:45:15 -05:00
Daniel Lemire 517143aec4 Update implementation-selection.md 2024-02-09 11:36:38 -05:00
Francisco Geiman Thiesen 9feda5e703 Update HACKING.md (#2122)
Updating windows command
2024-02-09 10:29:07 -05:00
Daniel Lemire cda198b7b9 Update ondemand_design.md 2024-02-09 10:22:44 -05:00
Daniel Lemire aad17a6a8d Update basics.md 2024-02-09 10:20:42 -05:00
Daniel Lemire 32d072a208 fixing issue2120 (#2121) 2024-02-08 11:34:36 -05:00
Daniel Lemire 5eab555053 documenting the support for custom types (#2098)
* documenting the support for custom types

* fixes

* getting around -Weffc++

* calling get_raw_json_string()

* documenting the support for custom types

* fixes

* getting around -Weffc++

* calling get_raw_json_string()
2024-02-06 13:20:35 -05:00
Daniel Lemire 6430fbd39a Better documentation and support for the case where you have a single implementation. (#2118) 2024-02-06 13:20:23 -05:00
Daniel Lemire 4d2fc31b27 removes simdjson.cpp include from the amalgated demo (#2119)
Co-authored-by: Daniel Lemire <dlemire@lemire.me>
2024-02-05 19:34:50 -05:00
Bo Anderson 33610b59eb Allow some iterators to be used in standard C++ iterator functions (#2106) 2024-02-05 17:52:01 -05:00
Daniel Lemire 23290ae48d retiring deprecated DOM APIs (#2109) 2024-02-04 21:58:48 -05:00
Daniel Lemire eb3a085e0f Bash check is unneeded. (#2112) 2024-02-04 21:58:36 -05:00
Daniel Lemire 4c8ec35a48 fixing the order of the apple counters 2024-01-31 14:30:44 -05:00
Daniel Lemire 88bf5cb6d9 version bump 2024-01-29 10:43:12 -05:00
Niles Salter 9b0435d864 [utf8-validator] eliminate unnecessary comparison from must_be_2_3_continuation (#2113)
* [utf8-validator] eliminate unnecessary comparison from must_be_2_3_continuation

* Fix comment in
2024-01-28 12:42:59 -05:00
Daniel Lemire ddecadde86 Update README.md 2024-01-23 09:35:12 -05:00
Bo Anderson 02bee7d1b9 Add load_into_document to simdjson::dom::parser (#2103) 2024-01-08 20:30:26 -05:00
Daniel Lemire 6ef555e6fb This PR updates the backup string_view implementation. It also adds a few comments to our README.md file. (#2105)
* This PR updates the backup string_view implementation. It also adds a few comments to our README.md file.

* removing trailing space
2024-01-08 14:52:00 -05:00
Daniel Lemire 6952f8dfce adding gcc 13 (#2101) 2024-01-04 18:57:44 -05:00
Daniel Lemire 03d0a4731a Update README.md 2024-01-03 17:49:43 -05:00
Daniel Lemire 185ff4e8fe Update basics.md 2023-12-29 09:35:35 -05:00
Daniel Lemire 5bf6d9f3f0 Update README.md 2023-12-29 09:30:01 -05:00
Daniel Lemire 2fa729922e fix for issue 2099 (#2100)
* fix for issue 2099

* avoid exceptions.

* fix for exception-less code
2023-12-19 12:15:59 -05:00
Daniel Lemire ebd09cb2a3 Update basics.md 2023-12-15 08:29:16 -05:00
Dirk Stolle 3978b9f159 update actions/checkout in GitHub Actions to v4 (#2095) 2023-12-09 23:21:28 -05:00
Dirk Stolle edc36a87ab fix a small typo (#2096) 2023-12-09 23:20:51 -05:00
Daniel Lemire 6060be2fdf version bump 2023-12-08 12:09:45 -05:00
Daniel Lemire 3251f61c9d fix for issue 2093 (#2094) 2023-12-07 12:42:28 -05:00
Ikraduya Edian 561ffcd519 Add benchmarks for boost json (#2092) 2023-12-04 10:33:53 -05:00
Daniel Lemire 5541e78402 version bump 2023-12-01 13:56:12 -05:00
Daniel Lemire 9a9ed0e2da Fix Visual Studio 64-bit ARM regression (#2091)
* fix for ARM64 kernel under Visual Studio (bug introduced in release 3.6.1)

* revert comment

* updating amal.
2023-12-01 13:55:28 -05:00
Daniel Lemire bca8d3e277 version bump. 2023-11-30 18:13:02 -05:00
Daniel Lemire 97196fa969 Fixing warnings issued by clang (Node issue 50930) (#2090)
* Fixing warnings issued by clang (Node issue 50930)

* removing space

---------

Co-authored-by: Daniel Lemire <dlemire@lemire.me>
2023-11-30 18:06:50 -05:00
John Keiser 23fab307ca Merge pull request #2088 from luhenry/upstream-riscv64
Make simdjson riscv64 aware
2023-11-30 11:06:43 -08:00
Daniel Lemire 0a14e05ec7 Update README.md 2023-11-30 13:42:00 -05:00
Daniel Lemire b88f831dbd Update basics.md 2023-11-30 11:52:24 -05:00
Daniel Lemire 71a73c2c47 Update basics.md 2023-11-30 11:51:35 -05:00
Daniel Lemire 07603aa7f7 fix space 2023-11-29 18:57:37 -05:00
Ludovic Henry b8a6b889c7 review: Revert changes in include/simdjson/implementation_detection.h 2023-11-29 22:09:25 +00:00
Ludovic Henry 7898234bb3 Make simdjson riscv64 aware 2023-11-29 19:28:14 +00:00
Daniel Lemire f52533538a Update basics.md 2023-11-28 23:49:40 -05:00
Daniel Lemire 3bb2f0a186 Return a better error when a user tries to cast a document that has already been accessed to a value (#2085)
* Fix.

* adding a test, cleaning some comments, adding documentation

* Correcting the JSON input.

* adding another test
2023-11-26 14:13:05 -05:00
Daniel Lemire d6551bf278 Update README.md 2023-11-22 11:36:33 -05:00
Daniel Lemire 0173eaaad7 Macro-based workaround for Visual Studio ARM (#2082) 2023-11-20 09:58:50 -05:00
Daniel Lemire 5459dbd6c6 typos. 2023-11-13 21:48:21 -05:00
Saint 9c45f1f292 Added link to Nim bindings (#2081) 2023-11-11 04:06:32 -05:00
int mian 665cbba159 fix typo (#2080) 2023-11-06 07:34:12 -05:00
Daniel Lemire a26f664907 removing space 2023-10-30 12:56:26 -04:00
Daniel Lemire 17cb457ffd version bump 2023-10-30 12:52:49 -04:00
Daniel Lemire 8b2af0473a skip UTF-8 BOM if present. (#2079) 2023-10-30 12:51:02 -04:00
Daniel Lemire f1bfa43385 Update ubuntu20-sani.yml 2023-10-27 20:58:54 -04:00
Daniel Lemire 29fbbee852 version bump 2023-10-27 20:57:30 -04:00
Daniel Lemire baa7d961ce Allowing users to write directly to std::optional<std::string> (#2078)
* Allowing users to write directly to std::optional<std::string>

* better fallback

* do not force the cast to std::string

* missing header

* removing abort
2023-10-27 20:56:12 -04:00
Yagiz Nizipli 6412b27c7e Merge pull request #2077 from simdjson/raw_json_on_values 2023-10-27 19:11:01 -04:00
Daniel Lemire 503da5ec83 raw_json() on values 2023-10-27 16:22:22 -04:00
Daniel Lemire 9dd6e9c959 version bump 2023-10-25 19:35:51 -04:00
Daniel Lemire 6db330c1a2 Automating string reallocation when it is possible (#2076)
* Automating string reallocation

* Typo
2023-10-25 19:34:52 -04:00
Daniel Lemire 993ac4b87c Adding the ability to write directly to an std::string. It is mostly syntaxic sugar (#2075) 2023-10-25 19:32:12 -04:00
Daniel Lemire 35e87896f0 minor tweak 2023-10-25 10:50:27 -04:00
Daniel Lemire f7e281cadc removing noisy warning 2023-10-20 15:45:40 -04:00
Daniel Lemire 13405afd4b This provides verbose static_assert messages (#2074)
* This provides verbose static_assert messages

* minor fix
2023-10-20 15:42:18 -04:00
Daniel Lemire 24b44309fb Removing commented code 2023-10-15 14:56:32 -04:00
Momtchil Momtchev e11ad58aad add a total order for elements (#2072) 2023-10-09 15:41:57 -04:00
Daniel Lemire 1875ed6550 Version bump. 2023-09-20 10:13:47 -04:00
Daniel Lemire 80d26298a0 Redesigning visit_primitive so that it is optimized for strings and (#2060)
numbers.

Co-authored-by: Daniel Lemire <dlemire@lemire.me>
2023-09-20 10:09:56 -04:00
Antoine Prouvost 25b5015c09 Add simdjson_static lib (#2068)
* Add simdjson_static lib

* Make simdjson_static a separate optional export file
2023-09-20 10:09:27 -04:00
Antoine Prouvost 26f8c566c7 Fix issue template bold text (#2067) 2023-09-19 11:15:54 -04:00
Daniel Lemire ff77ac801e Additional documentation based on issue 2063 (#2065)
* Additional documentation based on issue 2063

* Update basics.md
2023-09-11 10:01:35 -04:00
Daniel Lemire e0699994ef Testing macOS shared library support (#2062) 2023-09-09 12:48:42 -04:00
Daniel Lemire 68ba9a1b2a Adding a few spaces (minor formatting) (#2059) 2023-08-30 20:23:58 -04:00
Daniel Lemire 6fed6bd29b Update README.md 2023-08-30 19:26:34 -04:00
Piotr Rżysko cc24bb4114 Removed number parsing fallback (#2056) 2023-08-29 18:28:21 -04:00
John Keiser 14ec0ca8f4 Merge pull request #2052 from simdjson/jkeiser/structural_indexer_step
Write out 4 structural indexes at a time instead of 8
2023-08-29 15:24:54 -07:00
John Keiser 8dabd02c3a Default to step = 4 2023-08-29 15:48:52 -04:00
Daniel Lemire c9692005fd This allows us to pass SIMDJSON_STRUCTURAL_INDEXER_STEP as a command-line option. (#2055) 2023-08-25 13:47:20 -04:00
Daniel Lemire 2e0a9397c9 Merge branch 'master' into jkeiser/structural_indexer_step 2023-08-25 11:34:13 -04:00
Daniel Lemire f7922075c3 Adding support for Apple event counters (#2054) 2023-08-25 11:33:24 -04:00
Daniel Lemire b2e20e04c9 Standard compatibility fixes (#2053)
* Standard compatibility fixes

* missing commit

* Should work.

* Fix.

* Fix.

* Should work now.

---------

Co-authored-by: Daniel Lemire <dlemire@lemire.me>
2023-08-25 10:18:02 -04:00
John Keiser adc9d18efd Change step for structural_indexes to 2 2023-08-23 19:02:05 -07:00
Daniel Lemire bf849e3619 Preparing release 2023-08-22 14:05:14 -04:00
Daniel Lemire c09e8dc225 Icelake processes 64 bytes at a time when processing strings. (#2050)
Co-authored-by: Daniel Lemire <dlemire@lemire.me>
2023-08-18 14:37:10 -04:00
Daniel Lemire 5bf585ef02 Fixing failing thread sanitizer (#2051) 2023-08-18 14:35:12 -04:00
Daniel Lemire caff09cafc Update iterate_many.md 2023-08-14 12:18:09 -04:00
Daniel Lemire f043db4dca Preparing release. 2023-08-02 16:01:39 -04:00
Daniel Lemire e3bd0828d1 Fix for issue 2045. (#2046)
* Fix for issue 2045.

* Retauring single-header code.
2023-08-02 16:00:45 -04:00
John Keiser 9408298e0e Merge pull request #2042 from simdjson/jkeiser/escape3
New escape algorithm with significantly less data dependency
2023-08-02 10:38:09 -07:00
John Keiser 573bbac2d2 Reamalgamate again 2023-08-02 08:28:35 -07:00
John Keiser ac78c625df simdjson_inline -> simdjson_really_inline 2023-08-02 08:28:05 -07:00
John Keiser 390a66c6e8 Make next_structurals inline 2023-08-02 08:28:05 -07:00
John Keiser 210e0a56a1 Reamalgamate 2023-08-02 08:28:05 -07:00
John Keiser 084f662f32 Don't use C++20 designated initializers 2023-08-02 08:28:05 -07:00
John Keiser c878ff2500 Fix compiler warnings 2023-08-02 08:28:05 -07:00
John Keiser 06afe9ecb3 New escape algorithm with significantly less data dependency 2023-08-02 08:28:05 -07:00
Daniel Lemire e658502adb We are having issues with llvm.sh (#2044) 2023-08-02 11:24:28 -04:00
Daniel Lemire 6e7d415040 These lines should not be necessary. (#2043) 2023-08-01 19:33:27 -04:00
John Keiser 2ccd5b9c97 Merge pull request #2039 from simdjson/jkeiser/more-headers
Disallow including headers from implementation files
2023-07-21 12:09:57 -07:00
Daniel Lemire 1cdcbf79b3 We do actually support legacy 32-bit systems, although not with fast kernels. (#2041) 2023-07-21 13:53:10 -04:00
Calum McConnell 7013ed98cc Peek(0) is an error on 32-bit systems, where pointers are indistinguishable from int32_t (#2040) 2023-07-21 13:52:53 -04:00
John Keiser b383c717d7 Have amalgamate.py verify it's actually amalgamating all the files 2023-07-20 15:11:52 -07:00
John Keiser b8743bced0 Fix amalgamate.py under python 3.7 2023-07-20 14:14:44 -07:00
John Keiser ae9ba2bed2 Rename SIMDJSON_AMALGAMATED to SIMDJSON_CONDITIONAL_INCLUDE 2023-07-20 11:43:19 -07:00
Daniel Lemire 939844d79f Adding tests for issue 2037. (#2038)
* Adding tests for issue 2037.

* Fixed typo

* Simplifying.
2023-07-20 14:11:33 -04:00
John Keiser 4f4e81668e Change all include paths to <> instead of "" to avoid relative path includes 2023-07-20 10:48:25 -07:00
John Keiser bb54946b78 Disallow including headers from implementation files 2023-07-20 10:01:22 -07:00
John Keiser 4dec6ed5a7 Merge pull request #2036 from simdjson/jkeiser/more-header-fixes
A few more header fixes
2023-07-18 10:26:40 -07:00
John Keiser 1dfd48195d Merge pull request #2035 from simdjson/jkeiser/sanitizer-ci
Run sanitizers in parallel
2023-07-17 23:37:34 -07:00
John Keiser 23afc6b695 Merge branch 'master' into jkeiser/sanitizer-ci 2023-07-17 16:09:20 -07:00
John Keiser e3cac71afe Enforce that dependencies.h and generic/*.h include the same dependencies. 2023-07-17 16:07:42 -07:00
John Keiser cbe562c1d5 Fix header define names for inline files 2023-07-17 13:55:07 -07:00
John Keiser 30437d0ff6 A few header fixes for dom and ondemand 2023-07-17 13:53:50 -07:00
John Keiser 1e97af7dfb Merge pull request #2031 from simdjson/jkeiser/vscode-green
Get headers compiling in editor
2023-07-17 13:07:20 -07:00
John Keiser 80bc9e5051 Run sanitizers in parallel 2023-07-17 12:57:50 -07:00
John Keiser a74e87df17 Merge pull request #2026 from Cuda-Chen/pretty-print-for-dom
Add pretty print for DOM
2023-07-17 12:38:20 -07:00
John Keiser 3274299647 Merge pull request #2030 from yongxiangng/lazy-log-error
Add info and error logging, defer log message evaluation
2023-07-17 12:38:05 -07:00
John Keiser 22ca25faa6 Reamalgamate; make amalgamation normalize paths 2023-07-17 11:27:43 -07:00
John Keiser 37399fd41b Merge pull request #2034 from simdjson/add_add_emul_for_32bits
Adding missing umul
2023-07-17 10:02:55 -07:00
Daniel Lemire a170145d5b Missing header. 2023-07-17 11:48:07 -04:00
Daniel Lemire 7d1d635883 Adding missing umul 2023-07-17 10:04:57 -04:00
John Keiser ddfa8ae928 Reamalgamate 2023-07-16 22:53:42 -07:00
John Keiser 25dfb078c7 A few random header include ordering fixes 2023-07-16 22:50:54 -07:00
John Keiser 9f0710e3ad Move full_multiplication to <implementation>/numberparsing_defs.h 2023-07-16 22:34:21 -07:00
John Keiser 19b9cd9b05 Explain new directory structure 2023-07-16 21:42:50 -07:00
John Keiser 7540248396 Include simdprune_tables.h in generic implementations 2023-07-16 19:19:10 -07:00
John Keiser ab09e96de9 Only use amalgamated.h in generic/ 2023-07-16 19:18:58 -07:00
John Keiser 66252e4925 Honor --output-on-failure again 2023-07-15 17:44:44 -07:00
John Keiser 944778c186 Reamalgamate 2023-07-15 17:30:42 -07:00
John Keiser 62868a2f53 Catch more headers without which it won't compile 2023-07-15 17:16:18 -07:00
John Keiser 3c446c551b Move AMALGAMATED up to include implementation.cpp 2023-07-15 17:04:14 -07:00
John Keiser efe3d4b7d7 Few more missing headers, make it even stricter 2023-07-15 16:55:27 -07:00
John Keiser 28db262b47 Make SIMDJSON_AMALGAMATED checking much stricter 2023-07-15 16:46:15 -07:00
John Keiser bf076bfb5f Begin amalgamation early in simdjson.cpp 2023-07-15 15:55:38 -07:00
John Keiser 7bf1ecff9e Mark amalgamation early in 2023-07-15 15:53:09 -07:00
John Keiser e25a40facf Check if amalgamation rules are not being followed while compiling 2023-07-15 15:47:14 -07:00
John Keiser a442842f0d Use SIMDJSON_AMALGAMATED (which works in-editor and out) instead of editor-specific tweaks 2023-07-15 14:53:02 -07:00
John Keiser 421ed4f390 Try to make output on failure actually work 2023-07-14 20:57:24 -07:00
John Keiser 7dff5fa37c Include intrin.h from jsoncharutils.h since it's needed 2023-07-14 20:53:47 -07:00
John Keiser 9a0527c380 Only make editor stuff work in editor 2023-07-14 20:05:05 -07:00
John Keiser b160cf0610 Make simdjson.cpp compile on VSCode 2023-07-08 11:53:58 -07:00
John Keiser 553ee69b7c Make implementation .h/.cpp compile 2023-07-08 11:42:57 -07:00
John Keiser bf70cd0ebf Get headers compiling in editor 2023-07-08 10:47:15 -07:00
Cuda-Chen cf0551edf5 Add pretty print for DOM
Add pretty print for DOM with documentation.
Currently, the indentation is fixed to four spaces.

Close #1329.
2023-07-08 21:09:57 +08:00
yongxiangng ddb094d550 Move should log into separate if clause 2023-07-08 13:07:25 +08:00
Yong Xiang Ng 975fdda03c Add fine grain logging 2023-07-07 12:11:27 +08:00
Daniel Lemire c5c43e9c7f Release 2023-07-06 21:48:59 -04:00
Daniel Lemire 031ee32969 Undoing PR 2004 due to performance concerns. (#2029)
* Undoing PR 2004 due to performance concerns.

Fixes https://github.com/simdjson/simdjson/issues/2028
Fixes https://github.com/simdjson/simdjson/issues/2021

* Adding final lines.

---------

Co-authored-by: Daniel Lemire <dlemire@lemire.me>
2023-07-06 21:34:14 -04:00
John Keiser b613326d69 Merge pull request #2027 from simdjson/jkeiser/number_type-namespace
Move numberparsing functions to architecture top level
2023-07-06 12:52:16 -07:00
John Keiser 53dad74d8e Don't put number_type into ondemand 2023-07-05 14:26:23 -07:00
John Keiser e4da19f5cf Make more prominent hacking quickstart 2023-07-05 13:36:47 -07:00
John Keiser 342b58986a Add clangd file for VS Code 2023-07-05 13:13:32 -07:00
Daniel Lemire 7edc475886 Update README.md 2023-07-03 18:46:21 -04:00
Dirk Stolle d2f8e84fc1 update various actions in GitHub Actions to v3 (#2024)
The updated actions are actions/cache, actions/checkout and
actions/upload-artifact.
2023-06-26 09:09:09 -04:00
Dirk Stolle 08000518cb Fix some typos (#2025) 2023-06-26 08:37:52 -04:00
Daniel Lemire 90040d96a5 Update basics.md 2023-06-22 21:38:45 -04:00
Daniel Lemire 2934892c0b Improving documentation. (#2020)
* Improving documentation.

* Fix typo

* Moving the definition.

* [skip ci] typo
2023-06-20 13:51:53 -04:00
330 changed files with 116518 additions and 26783 deletions
+46
View File
@@ -0,0 +1,46 @@
CompileFlags:
CompilationDatabase: build
Add:
- -Werror -Wall -Wextra -Weffc++ -Wsign-compare -Wshadow -Wwrite-strings -Wpointer-arith -Winit-self -Wconversion -Wno-sign-conversion
- -Wundefined-inline
Diagnostics:
Suppress:
- misc-unused-alias-decls
- misc-unused-using-decls
- misc-definitions-in-headers # TODO fix and remove these violations
---
If:
PathMatch:
- include/.*
- src/.*
PathExclude:
- include/simdjson.h
- src/simdjson.cpp
CompileFlags:
Add:
- -Wno-unneeded-internal-declaration
- -Wno-undefined-internal # TODO fix and remove these violations
- -Wno-unused-function
- -Wno-unused-const-variable
Diagnostics:
Suppress:
- pp_including_mainfile_in_preamble
---
# Amalgamated files that require or partly define an implementation
If:
PathMatch:
- .*/(arm64|fallback|haswell|icelake|ppc64|westmere)/begin.h
- .*/generic/.*
Diagnostics:
Suppress:
- pragma_attribute_no_pop_eof
---
# clang has a bad time detecting the push/pop together in src/ for some reason
If:
PathMatch:
- include/simdjson/.*/end.h
- src/(arm64|fallback|haswell|icelake|ppc64|westmere).cpp
Diagnostics:
Suppress:
- pragma_attribute_no_pop_eof
- pragma_attribute_stack_mismatch
+6 -2
View File
@@ -45,11 +45,15 @@ It is fine to report bugs against our main branch, but if that is what you are d
**Configuration (please complete the following information if relevant)** **Configuration (please complete the following information if relevant)**
- OS: [e.g. Ubuntu 16.04.6 LTS] - OS: [e.g. Ubuntu 16.04.6 LTS]
- Compiler [e.g. Apple clang version 11.0.3 (clang-1103.0.32.59) x86_64-apple-darwin19.4.0] - Compiler* [e.g. Apple clang version 11.0.3 (clang-1103.0.32.59) x86_64-apple-darwin19.4.0]
- Version [e.g. 22] - Version [e.g. 22]
- Optimization setting (e.g., -O3) - Optimization setting (e.g., -O3)
We support up-to-date 64-bit ARM and x64 FreeBSD, macOS, Windows and Linux systems. Please ensure that your configuration is supported before labelling the issue as a bug. In particular, we do not support legacy 32-bit systems. We support up-to-date 64-bit ARM and x64 FreeBSD, macOS, Windows and Linux systems. Please ensure that your configuration is supported before labelling the issue as a bug.
* We do not support unreleased or experimental compilers. If you encounter an issue with a
pre-release version of a compiler, do not report it as a bug to simdjson. However, we always
invite contributions either in the form an analysis or of a code contribution.
**Indicate whether you are willing or able to provide a bug fix as a pull request** **Indicate whether you are willing or able to provide a bug fix as a pull request**
+1 -1
View File
@@ -31,7 +31,7 @@ A clear and concise description of any alternative solutions or features you've
**Additional context** **Additional context**
Add any other context or screenshots about the feature request here. Add any other context or screenshots about the feature request here.
** Are you willing to contribute code or documentation toward this new feature? ** **Are you willing to contribute code or documentation toward this new feature?**
If you plan to contribute to simdjson, please read our If you plan to contribute to simdjson, please read our
* CONTRIBUTING guide: https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md and our * CONTRIBUTING guide: https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md and our
* HACKING guide: https://github.com/simdjson/simdjson/blob/master/HACKING.md * HACKING guide: https://github.com/simdjson/simdjson/blob/master/HACKING.md
+2 -2
View File
@@ -9,7 +9,7 @@ jobs:
! contains(toJSON(github.event.commits.*.message), '[skip github]') ! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/cache@v3 - uses: actions/cache@v3
with: with:
path: dependencies/.cache path: dependencies/.cache
@@ -31,4 +31,4 @@ jobs:
./alpine.sh cmake --build build_for_alpine ./alpine.sh cmake --build build_for_alpine
- name: test - name: test
run: | run: |
./alpine.sh bash -c "cd build_for_alpine && ctest -LE explicitonly" ./alpine.sh bash -c "cd build_for_alpine && ctest -LE explicitonly --output-on-failure"
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
image: debian:testing image: debian:testing
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Install dependencies - name: Install dependencies
run: | run: |
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
url: ${{ steps.deployment.outputs.page_url }} url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Install Doxygen - name: Install Doxygen
run: sudo apt-get install doxygen graphviz -y run: sudo apt-get install doxygen graphviz -y
- run: mkdir docs - run: mkdir docs
@@ -6,7 +6,7 @@ jobs:
whitespace: whitespace:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Remove whitespace and check the diff - name: Remove whitespace and check the diff
run: | run: |
set -eu set -eu
+5 -4
View File
@@ -34,10 +34,11 @@ jobs:
sudo apt update sudo apt update
sudo apt-get install --quiet ninja-build valgrind zip unzip lsb-release wget software-properties-common gnupg sudo apt-get install --quiet ninja-build valgrind zip unzip lsb-release wget software-properties-common gnupg
wget https://apt.llvm.org/llvm.sh wget https://apt.llvm.org/llvm.sh
sudo apt-get purge --auto-remove llvm python3-lldb-14 llvm-14
chmod +x llvm.sh chmod +x llvm.sh
sudo ./llvm.sh $CLANGVERSION sudo ./llvm.sh $CLANGVERSION
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/cache@v3 - uses: actions/cache@v3
with: with:
@@ -124,7 +125,7 @@ jobs:
done done
- name: Save the corpus as a github artifact - name: Save the corpus as a github artifact
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v3
with: with:
name: corpus name: corpus
path: corpus.tar path: corpus.tar
@@ -147,7 +148,7 @@ jobs:
run: tar cf valgrind.tar valgrind-*.txt run: tar cf valgrind.tar valgrind-*.txt
- name: Save valgrind output as a github artifact - name: Save valgrind output as a github artifact
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v3
if: always() if: always()
with: with:
name: valgrindresults name: valgrindresults
@@ -155,7 +156,7 @@ jobs:
if-no-files-found: ignore if-no-files-found: ignore
- name: Archive any crashes as an artifact - name: Archive any crashes as an artifact
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v3
if: always() if: always()
with: with:
name: crashes name: crashes
+14 -3
View File
@@ -9,7 +9,7 @@ jobs:
! contains(toJSON(github.event.commits.*.message), '[skip github]') ! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: macos-latest runs-on: macos-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/cache@v3 - uses: actions/cache@v3
with: with:
path: dependencies/.cache path: dependencies/.cache
@@ -20,14 +20,25 @@ jobs:
cd builddebug && cd builddebug &&
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. && cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
cmake --build . && cmake --build . &&
ctest -j --output-on-failure -LE explicitonly && ctest --output-on-failure -LE explicitonly -j &&
cd .. && cd .. &&
mkdir build && mkdir build &&
cd build && cd build &&
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. && cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
cmake --build . && cmake --build . &&
ctest -j --output-on-failure -LE explicitonly && ctest --output-on-failure -LE explicitonly -j &&
cmake --install . && cmake --install . &&
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json && echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
cd ../tests/installation_tests/find && cd ../tests/installation_tests/find &&
mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../build/destination .. && cmake --build . mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../build/destination .. && cmake --build .
- name: Use cmake (shared)
run: |
mkdir buildshared &&
cd buildshared &&
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
cmake --build . &&
ctest --output-on-failure -LE explicitonly -j &&
cmake --install . &&
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
cd ../tests/installation_tests/find &&
mkdir buildshared && cd buildshared && cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../buildshared/destination .. && cmake --build .
+1 -1
View File
@@ -24,7 +24,7 @@ jobs:
CMAKE_GENERATOR: Ninja CMAKE_GENERATOR: Ninja
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/cache@v3 - uses: actions/cache@v3
with: with:
path: dependencies/.cache path: dependencies/.cache
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
CMAKE_GENERATOR: Ninja CMAKE_GENERATOR: Ninja
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/cache@v3 - uses: actions/cache@v3
with: with:
path: dependencies/.cache path: dependencies/.cache
+1 -1
View File
@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
name: Build on ubuntu-20.04 ppc64le name: Build on ubuntu-20.04 ppc64le
steps: steps:
- uses: actions/checkout@v2.1.0 - uses: actions/checkout@v4
- uses: uraimo/run-on-arch-action@v2.0.5 - uses: uraimo/run-on-arch-action@v2.0.5
name: Run commands name: Run commands
id: runcmd id: runcmd
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: uraimo/run-on-arch-action@v2 - uses: uraimo/run-on-arch-action@v2
name: Test name: Test
id: runcmd id: runcmd
+29
View File
@@ -0,0 +1,29 @@
name: Ubuntu riscv64 (GCC 11)
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: uraimo/run-on-arch-action@v2
name: Test
id: runcmd
with:
arch: riscv64
distro: ubuntu_latest
githubToken: ${{ github.token }}
install: |
apt-get update -q -y
apt-get install -y cmake make g++
run: |
cmake -DCMAKE_BUILD_TYPE=Release -B build
cmake --build build -j=2
ctest --output-on-failure --test-dir build
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: uraimo/run-on-arch-action@v2 - uses: uraimo/run-on-arch-action@v2
name: Test name: Test
id: runcmd id: runcmd
+1 -1
View File
@@ -15,7 +15,7 @@ jobs:
! contains(toJSON(github.event.commits.*.message), '[skip github]') ! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/cache@v3 - uses: actions/cache@v3
with: with:
path: dependencies/.cache path: dependencies/.cache
+3 -3
View File
@@ -12,7 +12,7 @@ jobs:
CXX: g++-8 CXX: g++-8
CC: gcc-8 CC: gcc-8
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/cache@v3 - uses: actions/cache@v3
with: with:
path: dependencies/.cache path: dependencies/.cache
@@ -25,13 +25,13 @@ jobs:
cd builddebug && cd builddebug &&
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. && cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
cmake --build . && cmake --build . &&
ctest -j --output-on-failure -LE explicitonly && ctest --output-on-failure -LE explicitonly -j &&
cd .. && cd .. &&
mkdir build && mkdir build &&
cd build && cd build &&
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. && cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
cmake --build . && cmake --build . &&
ctest -j --output-on-failure -LE explicitonly && ctest --output-on-failure -LE explicitonly -j &&
cmake --install . && cmake --install . &&
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json && echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
cd ../tests/installation_tests/find && cd ../tests/installation_tests/find &&
+3 -3
View File
@@ -9,7 +9,7 @@ jobs:
! contains(toJSON(github.event.commits.*.message), '[skip github]') ! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/cache@v3 - uses: actions/cache@v3
with: with:
path: dependencies/.cache path: dependencies/.cache
@@ -20,13 +20,13 @@ jobs:
cd builddebug && cd builddebug &&
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_EXCEPTIONS=OFF -DBUILD_SHARED_LIBS=OFF .. && cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_EXCEPTIONS=OFF -DBUILD_SHARED_LIBS=OFF .. &&
cmake --build . && cmake --build . &&
ctest -j --output-on-failure -LE explicitonly && ctest --output-on-failure -LE explicitonly -j &&
cd .. && cd .. &&
mkdir build && mkdir build &&
cd build && cd build &&
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_EXCEPTIONS=OFF -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. && cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_EXCEPTIONS=OFF -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
cmake --build . && cmake --build . &&
ctest -j --output-on-failure -LE explicitonly && ctest --output-on-failure -LE explicitonly -j &&
make install && make install &&
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json && echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
mkdir testfindpackage && mkdir testfindpackage &&
+3 -3
View File
@@ -9,7 +9,7 @@ jobs:
! contains(toJSON(github.event.commits.*.message), '[skip github]') ! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/cache@v3 - uses: actions/cache@v3
with: with:
path: dependencies/.cache path: dependencies/.cache
@@ -20,13 +20,13 @@ jobs:
cd builddebug && cd builddebug &&
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_ENABLE_THREADS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. && cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_ENABLE_THREADS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
cmake --build . && cmake --build . &&
ctest -j --output-on-failure -LE explicitonly && ctest --output-on-failure -LE explicitonly -j &&
cd .. && cd .. &&
mkdir build && mkdir build &&
cd build && cd build &&
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_ENABLE_THREADS=OFF -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. && cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_ENABLE_THREADS=OFF -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
cmake --build . && cmake --build . &&
ctest -j --output-on-failure -LE explicitonly && ctest --output-on-failure -LE explicitonly -j &&
make install && make install &&
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json && echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
mkdir testfindpackage && mkdir testfindpackage &&
+15 -4
View File
@@ -3,13 +3,13 @@ name: Ubuntu 20.04 CI (GCC 9) With Memory Sanitizer
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
ubuntu-build: ubuntu-build-address-sanitizier:
if: >- if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') && ! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]') ! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/cache@v3 - uses: actions/cache@v3
with: with:
path: dependencies/.cache path: dependencies/.cache
@@ -20,11 +20,22 @@ jobs:
cd builddebug && cd builddebug &&
cmake -DSIMDJSON_SANITIZE=ON -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. && cmake -DSIMDJSON_SANITIZE=ON -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
cmake --build . && cmake --build . &&
ctest -j --output-on-failure -LE explicitonly ctest --output-on-failure -LE explicitonly -j
ubuntu-build-undefined-sanitizer:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- uses: actions/cache@v3
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Use cmake with undefined sanitizer - name: Use cmake with undefined sanitizer
run: | run: |
mkdir builddebugundefsani && mkdir builddebugundefsani &&
cd builddebugundefsani && cd builddebugundefsani &&
cmake -DSIMDJSON_SANITIZE_UNDEFINED=ON -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. && cmake -DSIMDJSON_SANITIZE_UNDEFINED=ON -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
cmake --build . && cmake --build . &&
ctest -j --output-on-failure -LE explicitonly ctest --output-on-failure -LE explicitonly -j
+17 -3
View File
@@ -9,24 +9,38 @@ jobs:
! contains(toJSON(github.event.commits.*.message), '[skip github]') ! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/cache@v3 - uses: actions/cache@v3
with: with:
path: dependencies/.cache path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }} key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Use cmake to build just the library
run: |
mkdir buildjustlib &&
cd buildjustlib &&
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_DEVELOPER_MODE=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
cmake --build . &&
cmake --install . &&
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp &&
c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson &&
cd ../tests/installation_tests/find &&
mkdir buildjustlib &&
cd buildjustlib &&
cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../buildjustlib/destination .. &&
cmake --build .
- name: Use cmake - name: Use cmake
run: | run: |
mkdir builddebug && mkdir builddebug &&
cd builddebug && cd builddebug &&
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. && cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
cmake --build . && cmake --build . &&
ctest -j --output-on-failure -LE explicitonly && ctest --output-on-failure -LE explicitonly -j &&
cd .. && cd .. &&
mkdir build && mkdir build &&
cd build && cd build &&
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. && cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
cmake --build . && cmake --build . &&
ctest -j --output-on-failure -LE explicitonly && ctest --output-on-failure -LE explicitonly -j &&
cmake --install . && cmake --install . &&
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json && echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
cd ../tests/installation_tests/find && cd ../tests/installation_tests/find &&
+2 -4
View File
@@ -9,17 +9,15 @@ jobs:
! contains(toJSON(github.event.commits.*.message), '[skip github]') ! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/cache@v3 - uses: actions/cache@v3
with: with:
path: dependencies/.cache path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }} key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Install clang++-13
run: sudo apt-get install -y clang++-13
- name: Use cmake - name: Use cmake
run: | run: |
mkdir build && mkdir build &&
cd build && cd build &&
CXX=clang++-13 cmake -DSIMDJSON_DEVELOPER_MODE=ON .. && CXX=clang++-13 cmake -DSIMDJSON_DEVELOPER_MODE=ON .. &&
cmake --build . && cmake --build . &&
ctest -j --output-on-failure -LE explicitonly ctest --output-on-failure -LE explicitonly -j
+2 -4
View File
@@ -9,17 +9,15 @@ jobs:
! contains(toJSON(github.event.commits.*.message), '[skip github]') ! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/cache@v3 - uses: actions/cache@v3
with: with:
path: dependencies/.cache path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }} key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Install clang++-14
run: sudo apt-get install -y clang++-14
- name: Use cmake - name: Use cmake
run: | run: |
mkdir build && mkdir build &&
cd build && cd build &&
CXX=clang++-14 cmake -DSIMDJSON_DEVELOPER_MODE=ON .. && CXX=clang++-14 cmake -DSIMDJSON_DEVELOPER_MODE=ON .. &&
cmake --build . && cmake --build . &&
ctest -j --output-on-failure -LE explicitonly ctest --output-on-failure -LE explicitonly -j
+4 -4
View File
@@ -9,8 +9,8 @@ jobs:
! contains(toJSON(github.event.commits.*.message), '[skip github]') ! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- uses: actions/cache@v2 - uses: actions/cache@v3
with: with:
path: dependencies/.cache path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }} key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
@@ -20,13 +20,13 @@ jobs:
cd builddebug && cd builddebug &&
CXX=g++-12 cmake -DSIMDJSON_CXX_STANDARD=20 -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. && CXX=g++-12 cmake -DSIMDJSON_CXX_STANDARD=20 -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
cmake --build . && cmake --build . &&
ctest -j --output-on-failure -LE explicitonly && ctest --output-on-failure -LE explicitonly -j &&
cd .. && cd .. &&
mkdir build && mkdir build &&
cd build && cd build &&
CXX=g++-12 cmake -DSIMDJSON_CXX_STANDARD=20 -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. && CXX=g++-12 cmake -DSIMDJSON_CXX_STANDARD=20 -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
cmake --build . && cmake --build . &&
ctest -j --output-on-failure -LE explicitonly && ctest --output-on-failure -LE explicitonly -j &&
cmake --install . && cmake --install . &&
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json && echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
cd ../tests/installation_tests/find && cd ../tests/installation_tests/find &&
+2 -4
View File
@@ -9,17 +9,15 @@ jobs:
! contains(toJSON(github.event.commits.*.message), '[skip github]') ! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/cache@v3 - uses: actions/cache@v3
with: with:
path: dependencies/.cache path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }} key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Install gcc12
run: sudo apt-get install -y g++-12
- name: Use cmake - name: Use cmake
run: | run: |
mkdir build && mkdir build &&
cd build && cd build &&
CXX=g++-12 cmake -DSIMDJSON_DEVELOPER_MODE=ON .. && CXX=g++-12 cmake -DSIMDJSON_DEVELOPER_MODE=ON .. &&
cmake --build . && cmake --build . &&
ctest -j --output-on-failure -LE explicitonly ctest --output-on-failure -LE explicitonly -j
+23
View File
@@ -0,0 +1,23 @@
name: Ubuntu 22.04 CI (GCC 13)
on: [push, pull_request]
jobs:
ubuntu-build:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/cache@v3
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Use cmake
run: |
mkdir build &&
cd build &&
CXX=g++-13 cmake -DSIMDJSON_DEVELOPER_MODE=ON .. &&
cmake --build . &&
ctest --output-on-failure -LE explicitonly -j
@@ -8,7 +8,7 @@ jobs:
! contains(toJSON(github.event.commits.*.message), '[skip github]') ! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/cache@v3 - uses: actions/cache@v3
with: with:
path: dependencies/.cache path: dependencies/.cache
@@ -1,4 +1,4 @@
name: Ubuntu 20.04 CI (GCC 9) with Thread Sanitizer name: Ubuntu 22.04 CI (GCC 11) with Thread Sanitizer
on: [push, pull_request] on: [push, pull_request]
@@ -7,9 +7,9 @@ jobs:
if: >- if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') && ! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]') ! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-20.04 runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/cache@v3 - uses: actions/cache@v3
with: with:
path: dependencies/.cache path: dependencies/.cache
+17 -3
View File
@@ -9,24 +9,38 @@ jobs:
! contains(toJSON(github.event.commits.*.message), '[skip github]') ! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/cache@v3 - uses: actions/cache@v3
with: with:
path: dependencies/.cache path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }} key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Use cmake to build just the library
run: |
mkdir buildjustlib &&
cd buildjustlib &&
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_DEVELOPER_MODE=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
cmake --build . &&
cmake --install . &&
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp &&
c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson &&
cd ../tests/installation_tests/find &&
mkdir buildjustlib &&
cd buildjustlib &&
cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../buildjustlib/destination .. &&
cmake --build .
- name: Use cmake - name: Use cmake
run: | run: |
mkdir builddebug && mkdir builddebug &&
cd builddebug && cd builddebug &&
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. && cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
cmake --build . && cmake --build . &&
ctest -j --output-on-failure -LE explicitonly && ctest --output-on-failure -LE explicitonly -j &&
cd .. && cd .. &&
mkdir build && mkdir build &&
cd build && cd build &&
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. && cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
cmake --build . && cmake --build . &&
ctest -j --output-on-failure -LE explicitonly && ctest --output-on-failure -LE explicitonly -j &&
cmake --install . && cmake --install . &&
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json && echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
cd ../tests/installation_tests/find && cd ../tests/installation_tests/find &&
+1 -1
View File
@@ -14,7 +14,7 @@ jobs:
- {arch: ARM64} - {arch: ARM64}
steps: steps:
- name: checkout - name: checkout
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Use cmake - name: Use cmake
run: | run: |
cmake -A ${{ matrix.arch }} -DCMAKE_CROSSCOMPILING=1 -DSIMDJSON_DEVELOPER_MODE=ON -D SIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_EXCEPTIONS=OFF -B build && cmake -A ${{ matrix.arch }} -DCMAKE_CROSSCOMPILING=1 -DSIMDJSON_DEVELOPER_MODE=ON -D SIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_EXCEPTIONS=OFF -B build &&
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
- {gen: Visual Studio 17 2022, arch: x64, shared: OFF} - {gen: Visual Studio 17 2022, arch: x64, shared: OFF}
steps: steps:
- name: checkout - name: checkout
uses: actions/checkout@v2 uses: actions/checkout@v4
- name: Configure - name: Configure
run: | run: |
cmake -DSIMDJSON_CXX_STANDARD=20 -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -DBUILD_SHARED_LIBS=${{matrix.shared}} -B build cmake -DSIMDJSON_CXX_STANDARD=20 -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -DBUILD_SHARED_LIBS=${{matrix.shared}} -B build
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
- {gen: Visual Studio 17 2022, arch: x64, shared: OFF} - {gen: Visual Studio 17 2022, arch: x64, shared: OFF}
steps: steps:
- name: checkout - name: checkout
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Configure - name: Configure
run: | run: |
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -DBUILD_SHARED_LIBS=${{matrix.shared}} -B build cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -DBUILD_SHARED_LIBS=${{matrix.shared}} -B build
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
- {gen: Visual Studio 17 2022, arch: x64} - {gen: Visual Studio 17 2022, arch: x64}
steps: steps:
- name: checkout - name: checkout
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Configure - name: Configure
run: | run: |
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -T ClangCL -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -B build cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -T ClangCL -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -B build
+1 -1
View File
@@ -7,7 +7,7 @@ jobs:
name: windows-vs17 name: windows-vs17
runs-on: windows-latest runs-on: windows-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/cache@v3 - uses: actions/cache@v3
with: with:
path: dependencies/.cache path: dependencies/.cache
+3
View File
@@ -104,3 +104,6 @@ objs
!.vscode/tasks.json !.vscode/tasks.json
!.vscode/launch.json !.vscode/launch.json
!.vscode/extensions.json !.vscode/extensions.json
# clangd
.cache
+8 -3
View File
@@ -4,10 +4,15 @@
// List of extensions which should be recommended for users of this workspace. // List of extensions which should be recommended for users of this workspace.
"recommendations": [ "recommendations": [
// Syntax // C++
"ms-vscode.cpptools", "llvm-vs-code-extensions.vscode-clangd",
"ms-vscode.cmake-tools", "xaver.clang-format",
// Python
"ms-python.python", "ms-python.python",
// .github/*
"github.vscode-github-actions",
// cmake
"ms-vscode.cmake-tools",
"twxs.cmake" "twxs.cmake"
], ],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace. // List of extensions recommended by VS Code that should not be recommended for users of this workspace.
+7 -1
View File
@@ -5,6 +5,7 @@
], ],
"files.trimTrailingWhitespace": true, "files.trimTrailingWhitespace": true,
"files.associations": { "files.associations": {
".clangd": "yaml",
"array": "cpp", "array": "cpp",
"iterator": "cpp", "iterator": "cpp",
"chrono": "cpp", "chrono": "cpp",
@@ -97,6 +98,11 @@
"queue": "cpp", "queue": "cpp",
"shared_mutex": "cpp", "shared_mutex": "cpp",
"ranges": "cpp", "ranges": "cpp",
"span": "cpp" "span": "cpp",
"__verbose_abort": "cpp",
"charconv": "cpp",
"source_location": "cpp",
"strstream": "cpp",
"typeindex": "cpp"
} }
} }
+32 -5
View File
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
project( project(
simdjson simdjson
# The version number is modified by tools/release.py # The version number is modified by tools/release.py
VERSION 3.2.0 VERSION 3.7.0
DESCRIPTION "Parsing gigabytes of JSON per second" DESCRIPTION "Parsing gigabytes of JSON per second"
HOMEPAGE_URL "https://simdjson.org/" HOMEPAGE_URL "https://simdjson.org/"
LANGUAGES CXX C LANGUAGES CXX C
@@ -20,8 +20,10 @@ string(
# ---- Options, variables ---- # ---- Options, variables ----
# These version numbers are modified by tools/release.py # These version numbers are modified by tools/release.py
set(SIMDJSON_LIB_VERSION "16.0.0" CACHE STRING "simdjson library version") set(SIMDJSON_LIB_VERSION "20.0.0" CACHE STRING "simdjson library version")
set(SIMDJSON_LIB_SOVERSION "16" CACHE STRING "simdjson library soversion") set(SIMDJSON_LIB_SOVERSION "20" CACHE STRING "simdjson library soversion")
option(SIMDJSON_BUILD_STATIC_LIB "Build simdjson_static library along with simdjson" OFF)
option(SIMDJSON_ENABLE_THREADS "Link with thread support" ON) option(SIMDJSON_ENABLE_THREADS "Link with thread support" ON)
@@ -56,8 +58,17 @@ include(cmake/developer-options.cmake)
# ---- simdjson library ---- # ---- simdjson library ----
add_library(simdjson src/simdjson.cpp) set(SIMDJSON_SOURCES src/simdjson.cpp)
add_library(simdjson ${SIMDJSON_SOURCES})
add_library(simdjson::simdjson ALIAS simdjson) add_library(simdjson::simdjson ALIAS simdjson)
set(SIMDJSON_LIBRARIES simdjson)
if(SIMDJSON_BUILD_STATIC_LIB)
add_library(simdjson_static STATIC ${SIMDJSON_SOURCES})
add_library(simdjson::simdjson_static ALIAS simdjson_static)
list(APPEND SIMDJSON_LIBRARIES simdjson_static)
endif()
set_target_properties( set_target_properties(
simdjson PROPERTIES simdjson PROPERTIES
@@ -117,6 +128,9 @@ if(SIMDJSON_ENABLE_THREADS)
endif() endif()
simdjson_apply_props(simdjson) simdjson_apply_props(simdjson)
if(SIMDJSON_BUILD_STATIC_LIB)
simdjson_apply_props(simdjson_static)
endif()
# ---- Install rules ---- # ---- Install rules ----
@@ -138,7 +152,6 @@ install(
ARCHIVE COMPONENT simdjson_Development ARCHIVE COMPONENT simdjson_Development
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
) )
configure_file(cmake/simdjson-config.cmake.in simdjson-config.cmake @ONLY) configure_file(cmake/simdjson-config.cmake.in simdjson-config.cmake @ONLY)
write_basic_package_version_file( write_basic_package_version_file(
@@ -167,6 +180,20 @@ install(
COMPONENT simdjson_Development COMPONENT simdjson_Development
) )
if(SIMDJSON_BUILD_STATIC_LIB)
install(
TARGETS simdjson_static
EXPORT simdjson_staticTargets
ARCHIVE COMPONENT simdjson_Development
)
install(
EXPORT simdjson_staticTargets
NAMESPACE simdjson::
DESTINATION "${SIMDJSON_INSTALL_CMAKEDIR}"
COMPONENT simdjson_Development
)
endif()
# pkg-config # pkg-config
include(cmake/JoinPaths.cmake) include(cmake/JoinPaths.cmake)
join_paths(PKGCONFIG_INCLUDEDIR "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}") join_paths(PKGCONFIG_INCLUDEDIR "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
+2 -1
View File
@@ -52,10 +52,11 @@ General Guidelines
Contributors are encouraged to : Contributors are encouraged to :
- Document their changes. Though we do not enforce a rule regarding code comments, we prefer that non-trivial algorithms and techniques be somewhat documented in the code. - Document their changes. Though we do not enforce a rule regarding code comments, we prefer that non-trivial algorithms and techniques be somewhat documented in the code.
- Follow as much as possible the existing code style. We do not enforce a specific code style, but we prefer consistency. - Follow as much as possible the existing code style. We do not enforce a specific code style, but we prefer consistency. We avoid contractions (isn't, aren't) in the comments.
- Modify as few lines of code as possible when working on an issue. The more lines you modify, the harder it is for your fellow human beings to understand what is going on. - Modify as few lines of code as possible when working on an issue. The more lines you modify, the harder it is for your fellow human beings to understand what is going on.
- Tools may report "problems" with the code, but we never delegate programming to tools: if there is a problem with the code, we need to understand it. Thus we will not "fix" code merely to please a static analyzer. - Tools may report "problems" with the code, but we never delegate programming to tools: if there is a problem with the code, we need to understand it. Thus we will not "fix" code merely to please a static analyzer.
- Provide tests for any new feature. We will not merge a new feature without tests. - Provide tests for any new feature. We will not merge a new feature without tests.
- Run before/after benchmarks so that we can appreciate the effect of the changes on the performance.
Pull Requests Pull Requests
-------------- --------------
+1 -1
View File
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = "3.2.0" PROJECT_NUMBER = "3.7.0"
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a
+37 -19
View File
@@ -6,16 +6,26 @@ Here is wisdom about how to build, test and run simdjson from within the reposit
If you plan to contribute to simdjson, please read our [CONTRIBUTING](https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md) guide. If you plan to contribute to simdjson, please read our [CONTRIBUTING](https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md) guide.
- [Hacking simdjson](#hacking-simdjson)
- [Build Quickstart](#build-quickstart)
- [Design notes](#design-notes) - [Design notes](#design-notes)
- [Developer mode](#developer-mode) - [Developer mode](#developer-mode)
- [Directory Structure and Source](#directory-structure-and-source) - [Directory Structure and Source](#directory-structure-and-source)
- [Runtime Dispatching](#runtime-dispatching) - [Runtime Dispatching](#runtime-dispatching)
- [Regenerating Single-Header Files](#regenerating-single-header-files) - [Regenerating Single-Header Files](#regenerating-single-header-files)
- [Usage (CMake on 64-bit platforms like Linux, FreeBSD or macOS)](#usage-cmake-on-64-bit-platforms-like-linux-freebsd-or-macos) - [Usage (CMake on 64-bit platforms like Linux, FreeBSD or macOS)](#usage-cmake-on-64-bit-platforms-like-linux-freebsd-or-macos)
- [Usage (CMake on 64-bit Windows using Visual Studio 2019)](#usage-cmake-on-64-bit-windows-using-visual-studio-2019) - [Usage (CMake on 64-bit Windows using Visual Studio 2019 or better)](#usage-cmake-on-64-bit-windows-using-visual-studio-2019-or-better)
- [Various References](#various-references) - [Various References](#various-references)
Build Quickstart
------------------------------
```bash
mkdir build
cd build
cmake -D SIMDJSON_DEVELOPER_MODE=ON ..
cmake --build .
```
Design notes Design notes
------------------------------ ------------------------------
@@ -63,26 +73,34 @@ simdjson's source structure, from the top level, looks like this:
* **CMakeLists.txt:** The main build system. * **CMakeLists.txt:** The main build system.
* **include:** User-facing declarations and inline definitions (most user-facing functions are inlined). * **include:** User-facing declarations and inline definitions (most user-facing functions are inlined).
* simdjson.h: A "main include" that includes files from include/simdjson/. This is equivalent to * simdjson.h: the `simdjson` namespace. A "main include" that includes files from include/simdjson/. This is equivalent to
the distributed simdjson.h. the distributed simdjson.h.
* simdjson/*.h: Declarations for public simdjson classes and functions. * simdjson/*.h: Declarations for public simdjson classes and functions.
* simdjson/*-inl.h: Definitions for public simdjson classes and functions. * simdjson/*-inl.h: Definitions for public simdjson classes and functions.
* simdjson/internal/*.h: the `simdjson::internal` namespace. Private classes and functions used by the rest of simdjson.
* simdjson/dom.h: the `simdjson::dom` namespace. Includes all public DOM classes.
* simdjson/dom/*.h: Declarations/definitions for individual DOM classes.
* simdjson/arm64|fallback|haswell|icelake|ppc64|westmere.h: `simdjson::<implementation>` namespace. Common implementation-specific tools like number and string parsing, as well as minification.
* simdjson/arm64|fallback|haswell|icelake|ppc64|westmere/*.h: implementation-specific functions such as , etc.
* simdjson/generic/*.h: the bulk of the actual code, written generically and compiled for each implementation, using functions defined in the implementation's .h files.
* simdjson/generic/dependencies.h: dependencies on common, non-implementation-specific simdjson classes. This will be included before including amalgamated.h.
* simdjson/generic/amalgamated.h: all generic ondemand classes for an implementation.
* simdjson/ondemand.h: the `simdjson::ondemand` namespace. Includes all public ondemand classes.
* simdjson/builtin.h: the `simdjson::builtin` namespace. Aliased to the most universal implementation available.
* simdjson/builtin/ondemand.h: the `simdjson::builtin::ondemand` namespace.
* simdjson/arm64|fallback|haswell|icelake|ppc64|westmere/ondemand.h: the `simdjson::<implementation>::ondemand` namespace. on demand compiled for the specific implementation.
* simdjson/generic/ondemand/*.h: individual on demand classes, generically written.
* simdjson/generic/ondemand/dependencies.h: dependencies on common, non-implementation-specific simdjson classes. This will be included before including amalgamated.h.
* simdjson/generic/ondemand/amalgamated.h: all generic ondemand classes for an implementation.
* **src:** The source files for non-inlined functionality (e.g. the architecture-specific parser * **src:** The source files for non-inlined functionality (e.g. the architecture-specific parser
implementations). implementations).
* simdjson.cpp: A "main source" that includes all implementation files from src/. This is * simdjson.cpp: A "main source" that includes all implementation files from src/. This is
equivalent to the distributed simdjson.cpp. equivalent to the distributed simdjson.cpp.
* arm64/|fallback/|haswell/|ppc64/|westmere/: Architecture-specific implementations. All functions are * *.cpp: other misc. implementations, such as `simdjson::implementation` and the minifier.
Each architecture defines its own namespace, e.g. simdjson::haswell. * arm64|fallback|haswell|icelake|ppc64|westmere.cpp: Architecture-specific parser implementations.
* generic/: Generic implementations of the simdjson parser. These files may be included and * generic/*.h: `simdjson::<implementation>` namespace. Generic implementation of the parser, particularly the `dom_parser_implementation`.
compiled multiple times, from whichever architectures use them. They assume they are already * generic/stage1/*.h: `simdjson::<implementation>::stage1` namespace. Generic implementation of the simd-heavy tokenizer/indexer pass of the simdjson parser. Used for the On Demand interface
enclosed in a namespace, e.g.: * generic/stage2/*.h: `simdjson::<implementation>::stage2` namespace. Generic implementation of the tape creator, which consumes the index from stage 1 and actually parses numbers and string and such. Used for the DOM interface.
```c++
namespace simdjson {
namespace haswell {
#include "generic/stage1/json_structural_indexer.h"
}
}
```
Other important files and directories: Other important files and directories:
* **.drone.yml:** Definitions for Drone CI. * **.drone.yml:** Definitions for Drone CI.
@@ -286,7 +304,7 @@ Though having Visual Studio installed is necessary, one can build simdjson using
- `mkdir build` - `mkdir build`
- `cd build` - `cd build`
- `cmake ..` - `cmake ..`
- `cmake --build . -config Release` - `cmake --build . --config Release`
Furthermore, if you have installed LLVM clang on Windows, for example as a component of Visual Studio 2019, you can configure and build simdjson using LLVM clang on Windows using cmake: Furthermore, if you have installed LLVM clang on Windows, for example as a component of Visual Studio 2019, you can configure and build simdjson using LLVM clang on Windows using cmake:
@@ -295,7 +313,7 @@ Furthermore, if you have installed LLVM clang on Windows, for example as a compo
- `mkdir build` - `mkdir build`
- `cd build` - `cd build`
- `cmake -T ClangCL ..` - `cmake -T ClangCL ..`
- `cmake --build . -config Release` - `cmake --build . --config Release`
## Various References ## Various References
+18 -9
View File
@@ -1,8 +1,6 @@
[![Ubuntu 20.04 CI](https://github.com/simdjson/simdjson/workflows/Ubuntu%2020.04%20CI%20(GCC%209)/badge.svg)](https://simdjson.org/plots.html) [![Ubuntu 20.04 CI](https://github.com/simdjson/simdjson/workflows/Ubuntu%2020.04%20CI%20(GCC%209)/badge.svg)](https://simdjson.org/plots.html)
![VS16-CI](https://github.com/simdjson/simdjson/workflows/VS16-CI/badge.svg)
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/simdjson.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:simdjson) [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/simdjson.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:simdjson)
![MinGW64-CI](https://github.com/simdjson/simdjson/workflows/MinGW64-CI/badge.svg)
[![][license img]][license] [![][license img]][license]
[![Doxygen Documentation](https://img.shields.io/badge/docs-doxygen-green.svg)](https://simdjson.github.io/simdjson/) [![Doxygen Documentation](https://img.shields.io/badge/docs-doxygen-green.svg)](https://simdjson.github.io/simdjson/)
@@ -31,6 +29,7 @@ Table of Contents
* [Real-world usage](#real-world-usage) * [Real-world usage](#real-world-usage)
* [Quick Start](#quick-start) * [Quick Start](#quick-start)
* [Documentation](#documentation) * [Documentation](#documentation)
* [Godbolt](#godbolt)
* [Performance results](#performance-results) * [Performance results](#performance-results)
* [Bindings and Ports of simdjson](#bindings-and-ports-of-simdjson) * [Bindings and Ports of simdjson](#bindings-and-ports-of-simdjson)
* [About simdjson](#about-simdjson) * [About simdjson](#about-simdjson)
@@ -42,8 +41,10 @@ Table of Contents
Real-world usage Real-world usage
---------------- ----------------
- [Node.js](https://nodejs.org/)
- [ClickHouse](https://github.com/ClickHouse/ClickHouse) - [ClickHouse](https://github.com/ClickHouse/ClickHouse)
- [Facebook/Meta Velox](https://velox-lib.io) - [Meta Velox](https://velox-lib.io)
- [Google Pax](https://github.com/google/paxml)
- [milvus](https://github.com/milvus-io/milvus) - [milvus](https://github.com/milvus-io/milvus)
- [Clang Build Analyzer](https://github.com/aras-p/ClangBuildAnalyzer) - [Clang Build Analyzer](https://github.com/aras-p/ClangBuildAnalyzer)
- [Shopify HeapProfiler](https://github.com/Shopify/heap-profiler) - [Shopify HeapProfiler](https://github.com/Shopify/heap-profiler)
@@ -57,6 +58,7 @@ Real-world usage
- [fastgltf](https://github.com/spnda/fastgltf) - [fastgltf](https://github.com/spnda/fastgltf)
- [vast](https://github.com/tenzir/vast) - [vast](https://github.com/tenzir/vast)
- [ada-url](https://github.com/ada-url/ada) - [ada-url](https://github.com/ada-url/ada)
- [fastgron](https://github.com/adamritter/fastgron)
If you are planning to use simdjson in a product, please work from one of our releases. If you are planning to use simdjson in a product, please work from one of our releases.
@@ -67,9 +69,9 @@ The simdjson library is easily consumable with a single .h and .cpp file.
0. Prerequisites: `g++` (version 7 or better) or `clang++` (version 6 or better), and a 64-bit 0. Prerequisites: `g++` (version 7 or better) or `clang++` (version 6 or better), and a 64-bit
system with a command-line shell (e.g., Linux, macOS, freeBSD). We also support programming system with a command-line shell (e.g., Linux, macOS, freeBSD). We also support programming
environments like Visual Studio and Xcode, but different steps are needed. environments like Visual Studio and Xcode, but different steps are needed. Users of clang++ may need to specify the C++ version (e.g., `c++ -std=c++17`) since clang++ tends to default on C++98.
1. Pull [simdjson.h](singleheader/simdjson.h) and [simdjson.cpp](singleheader/simdjson.cpp) into a 1. Pull [simdjson.h](singleheader/simdjson.h) and [simdjson.cpp](singleheader/simdjson.cpp) into a
directory, along with the sample file [twitter.json](jsonexamples/twitter.json). directory, along with the sample file [twitter.json](jsonexamples/twitter.json). You can download them with the `wget` utility:
``` ```
wget https://raw.githubusercontent.com/simdjson/simdjson/master/singleheader/simdjson.h https://raw.githubusercontent.com/simdjson/simdjson/master/singleheader/simdjson.cpp https://raw.githubusercontent.com/simdjson/simdjson/master/jsonexamples/twitter.json wget https://raw.githubusercontent.com/simdjson/simdjson/master/singleheader/simdjson.h https://raw.githubusercontent.com/simdjson/simdjson/master/singleheader/simdjson.cpp https://raw.githubusercontent.com/simdjson/simdjson/master/jsonexamples/twitter.json
@@ -94,6 +96,7 @@ int main(void) {
100 results. 100 results.
``` ```
Documentation Documentation
------------- -------------
@@ -105,11 +108,12 @@ Usage documentation is available:
how you can work with it. how you can work with it.
* [API](https://simdjson.github.io/simdjson/) contains the automatically generated API documentation. * [API](https://simdjson.github.io/simdjson/) contains the automatically generated API documentation.
Godbolt
-------------
Some users may want to browse code along with the compiled assembly. You want to check out the following lists of examples: Some users may want to browse code along with the compiled assembly. You want to check out the following lists of examples:
* [simdjson examples with errors handled through exceptions](https://godbolt.org/z/7G5qE4sr9)
* [simdjson examples with errors handled through exceptions](https://godbolt.org/z/98Kx9Kqjn) * [simdjson examples with errors without exceptions](https://godbolt.org/z/e9dWb9E4v)
* [simdjson examples with errors without exceptions](https://godbolt.org/z/PKG7GdbPo)
Performance results Performance results
------------------- -------------------
@@ -164,6 +168,7 @@ We distinguish between "bindings" (which just wrap the C++ code) and a port to a
- [simdjzon](https://github.com/travisstaloch/simdjzon): zig port. - [simdjzon](https://github.com/travisstaloch/simdjzon): zig port.
- [JSON-Simd](https://github.com/rawleyfowler/JSON-simd): Raku bindings. - [JSON-Simd](https://github.com/rawleyfowler/JSON-simd): Raku bindings.
- [JSON::SIMD](https://metacpan.org/pod/JSON::SIMD): Perl bindings; fully-featured JSON module that uses simdjson for decoding. - [JSON::SIMD](https://metacpan.org/pod/JSON::SIMD): Perl bindings; fully-featured JSON module that uses simdjson for decoding.
- [gemmaJSON](https://github.com/sainttttt/gemmaJSON): Nim JSON parser based on simdjson bindings.
About simdjson About simdjson
-------------- --------------
@@ -172,7 +177,11 @@ The simdjson library takes advantage of modern microarchitectures, parallelizing
instructions, reducing branch misprediction, and reducing data dependency to take advantage of each instructions, reducing branch misprediction, and reducing data dependency to take advantage of each
CPU's multiple execution cores. CPU's multiple execution cores.
Some people [enjoy reading our paper](https://arxiv.org/abs/1902.08318): A description of the design Our default front-end is called On Demand, and we wrote a paper about it:
- John Keiser, Daniel Lemire, [On-Demand JSON: A Better Way to Parse Documents?](http://arxiv.org/abs/2312.17149), Software: Practice and Experience (to appear)
Some people [enjoy reading the first (2019) simdjson paper](https://arxiv.org/abs/1902.08318): A description of the design
and implementation of simdjson is in our research article: and implementation of simdjson is in our research article:
- Geoff Langdale, Daniel Lemire, [Parsing Gigabytes of JSON per Second](https://arxiv.org/abs/1902.08318), VLDB Journal 28 (6), 2019. - Geoff Langdale, Daniel Lemire, [Parsing Gigabytes of JSON per Second](https://arxiv.org/abs/1902.08318), VLDB Journal 28 (6), 2019.
+7
View File
@@ -0,0 +1,7 @@
# Security Policy
## Reporting a Vulnerability
Please use the following contact information for reporting a vulnerability:
- [Daniel Lemire](https://github.com/lemire) - daniel@lemire.me
+3
View File
@@ -26,6 +26,9 @@ if (TARGET benchmark::benchmark)
if(TARGET nlohmann_json) if(TARGET nlohmann_json)
target_link_libraries(bench_ondemand PRIVATE nlohmann_json) target_link_libraries(bench_ondemand PRIVATE nlohmann_json)
endif() endif()
if(TARGET boostjson)
target_link_libraries(bench_ondemand PRIVATE boostjson)
endif()
endif() endif()
endif() endif()
File diff suppressed because it is too large Load Diff
-158
View File
@@ -473,28 +473,6 @@ static void twitter_count(State& state) {
} }
BENCHMARK(twitter_count); BENCHMARK(twitter_count);
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
SIMDJSON_PUSH_DISABLE_WARNINGS
SIMDJSON_DISABLE_DEPRECATED_WARNING
static void iterator_twitter_count(State& state) {
// Prints the number of results in twitter.json
padded_string json = padded_string::load(TWITTER_JSON);
ParsedJson pj = build_parsed_json(json);
for (simdjson_unused auto _ : state) {
ParsedJson::Iterator iter(pj);
// uint64_t result_count = doc["search_metadata"]["count"];
if (!iter.move_to_key("search_metadata")) { return; }
if (!iter.move_to_key("count")) { return; }
if (!iter.is_integer()) { return; }
int64_t result_count = iter.get_integer();
if (result_count != 100) { return; }
}
}
BENCHMARK(iterator_twitter_count);
SIMDJSON_POP_DISABLE_WARNINGS
#endif // SIMDJSON_DISABLE_DEPRECATED_API
static void twitter_default_profile(State& state) { static void twitter_default_profile(State& state) {
// Count unique users with a default profile. // Count unique users with a default profile.
dom::parser parser; dom::parser parser;
@@ -578,54 +556,6 @@ static void error_code_twitter_default_profile(State& state) noexcept {
} }
BENCHMARK(error_code_twitter_default_profile); BENCHMARK(error_code_twitter_default_profile);
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
SIMDJSON_PUSH_DISABLE_WARNINGS
SIMDJSON_DISABLE_DEPRECATED_WARNING
static void iterator_twitter_default_profile(State& state) {
// Count unique users with a default profile.
padded_string json;
auto error = padded_string::load(TWITTER_JSON).get(json);
if (error) { std::cerr << error << std::endl; return; }
ParsedJson pj = build_parsed_json(json);
for (simdjson_unused auto _ : state) {
set<string_view> default_users;
ParsedJson::Iterator iter(pj);
// for (dom::object tweet : doc["statuses"]) {
if (!(iter.move_to_key("statuses") && iter.is_array())) { return; }
if (iter.down()) { // first status
do {
// dom::object user = tweet["user"];
if (!(iter.move_to_key("user") && iter.is_object())) { return; }
// if (user["default_profile"]) {
if (iter.move_to_key("default_profile")) {
if (iter.is_true()) {
if (!iter.up()) { return; } // back to user
// default_users.insert(user["screen_name"]);
if (!(iter.move_to_key("screen_name") && iter.is_string())) { return; }
default_users.emplace(iter.get_string(), iter.get_string_length());
}
if (!iter.up()) { return; } // back to user
}
if (!iter.up()) { return; } // back to status
} while (iter.next()); // next status
}
if (default_users.size() != 86) { return; }
}
}
SIMDJSON_POP_DISABLE_WARNINGS
BENCHMARK(iterator_twitter_default_profile);
#endif // SIMDJSON_DISABLE_DEPRECATED_API
static void error_code_twitter_image_sizes(State& state) noexcept { static void error_code_twitter_image_sizes(State& state) noexcept {
// Count unique image sizes // Count unique image sizes
dom::parser parser; dom::parser parser;
@@ -680,92 +610,4 @@ static void parse_surrogate_pairs(State& state) {
} }
BENCHMARK(parse_surrogate_pairs); BENCHMARK(parse_surrogate_pairs);
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
SIMDJSON_PUSH_DISABLE_WARNINGS
SIMDJSON_DISABLE_DEPRECATED_WARNING
static void iterator_twitter_image_sizes(State& state) {
// Count unique image sizes
padded_string json;
auto error = padded_string::load(TWITTER_JSON).get(json);
if (error) { std::cerr << error << std::endl; return; }
ParsedJson pj = build_parsed_json(json);
for (simdjson_unused auto _ : state) {
set<tuple<uint64_t, uint64_t>> image_sizes;
ParsedJson::Iterator iter(pj);
// for (dom::object tweet : doc["statuses"]) {
if (!(iter.move_to_key("statuses") && iter.is_array())) { return; }
if (iter.down()) { // first status
do {
// dom::object media;
// not_found = tweet["entities"]["media"].get(media);
// if (!not_found) {
if (iter.move_to_key("entities")) {
if (!iter.is_object()) { return; }
if (iter.move_to_key("media")) {
if (!iter.is_array()) { return; }
// for (dom::object image : media) {
if (iter.down()) { // first media
do {
// for (auto [key, size] : dom::object(image["sizes"])) {
if (!(iter.move_to_key("sizes") && iter.is_object())) { return; }
if (iter.down()) { // first size
do {
iter.move_to_value();
// image_sizes.insert({ size["w"], size["h"] });
if (!(iter.move_to_key("w")) && !iter.is_integer()) { return; }
uint64_t width = iter.get_integer();
if (!iter.up()) { return; } // back to size
if (!(iter.move_to_key("h")) && !iter.is_integer()) { return; }
uint64_t height = iter.get_integer();
if (!iter.up()) { return; } // back to size
image_sizes.emplace(width, height);
} while (iter.next()); // next size
if (!iter.up()) { return; } // back to sizes
}
if (!iter.up()) { return; } // back to image
} while (iter.next()); // next image
if (!iter.up()) { return; } // back to media
}
if (!iter.up()) { return; } // back to entities
}
if (!iter.up()) { return; } // back to status
}
} while (iter.next()); // next status
}
if (image_sizes.size() != 15) { return; };
}
}
BENCHMARK(iterator_twitter_image_sizes);
#endif // SIMDJSON_DISABLE_DEPRECATED_API
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
static void print_json(State& state) noexcept {
// Prints the number of results in twitter.json
dom::parser parser;
padded_string json;
auto error = padded_string::load(TWITTER_JSON).get(json);
if (error) { std::cerr << error << std::endl; return; }
int code = json_parse(json, parser);
if (code) { cerr << error_message(code) << endl; return; }
for (simdjson_unused auto _ : state) {
std::stringstream s;
if (!parser.print_json(s)) { cerr << "print_json failed" << endl; return; }
}
}
BENCHMARK(print_json);
#endif // SIMDJSON_DISABLE_DEPRECATED_API
SIMDJSON_POP_DISABLE_WARNINGS
BENCHMARK_MAIN(); BENCHMARK_MAIN();
+11
View File
@@ -21,6 +21,10 @@ SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#endif #endif
#ifdef SIMDJSON_COMPETITION_BOOSTJSON
#include <boost/json.hpp>
#endif
// This has to be last, for reasons I don't yet understand // This has to be last, for reasons I don't yet understand
#include <benchmark/benchmark.h> #include <benchmark/benchmark.h>
@@ -33,6 +37,7 @@ SIMDJSON_POP_DISABLE_WARNINGS
#include "json2msgpack/sajson.h" #include "json2msgpack/sajson.h"
#endif // SIMDJSON_COMPETITION_ONDEMAND_SAJSON #endif // SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "json2msgpack/nlohmann_json.h" #include "json2msgpack/nlohmann_json.h"
#include "json2msgpack/boostjson.h"
#include "partial_tweets/simdjson_ondemand.h" #include "partial_tweets/simdjson_ondemand.h"
#include "partial_tweets/simdjson_dom.h" #include "partial_tweets/simdjson_dom.h"
@@ -48,6 +53,7 @@ SIMDJSON_POP_DISABLE_WARNINGS
#if SIMDJSON_COMPETITION_SAX #if SIMDJSON_COMPETITION_SAX
#include "partial_tweets/nlohmann_json_sax.h" #include "partial_tweets/nlohmann_json_sax.h"
#endif // SIMDJSON_COMPETITION_SAX #endif // SIMDJSON_COMPETITION_SAX
#include "partial_tweets/boostjson.h"
#include "distinct_user_id/simdjson_ondemand.h" #include "distinct_user_id/simdjson_ondemand.h"
@@ -66,6 +72,7 @@ SIMDJSON_POP_DISABLE_WARNINGS
#if SIMDJSON_COMPETITION_SAX #if SIMDJSON_COMPETITION_SAX
#include "distinct_user_id/nlohmann_json_sax.h" #include "distinct_user_id/nlohmann_json_sax.h"
#endif // SIMDJSON_COMPETITION_SAX #endif // SIMDJSON_COMPETITION_SAX
#include "distinct_user_id/boostjson.h"
#include "find_tweet/simdjson_ondemand.h" #include "find_tweet/simdjson_ondemand.h"
#include "find_tweet/simdjson_dom.h" #include "find_tweet/simdjson_dom.h"
@@ -81,6 +88,7 @@ SIMDJSON_POP_DISABLE_WARNINGS
#if SIMDJSON_COMPETITION_SAX #if SIMDJSON_COMPETITION_SAX
#include "find_tweet/nlohmann_json_sax.h" #include "find_tweet/nlohmann_json_sax.h"
#endif // SIMDJSON_COMPETITION_SAX #endif // SIMDJSON_COMPETITION_SAX
#include "find_tweet/boostjson.h"
#include "top_tweet/simdjson_ondemand.h" #include "top_tweet/simdjson_ondemand.h"
#include "top_tweet/simdjson_dom.h" #include "top_tweet/simdjson_dom.h"
@@ -96,6 +104,7 @@ SIMDJSON_POP_DISABLE_WARNINGS
#if SIMDJSON_COMPETITION_SAX #if SIMDJSON_COMPETITION_SAX
#include "top_tweet/nlohmann_json_sax.h" #include "top_tweet/nlohmann_json_sax.h"
#endif // SIMDJSON_COMPETITION_SAX #endif // SIMDJSON_COMPETITION_SAX
#include "top_tweet/boostjson.h"
#include "kostya/simdjson_ondemand.h" #include "kostya/simdjson_ondemand.h"
@@ -112,6 +121,7 @@ SIMDJSON_POP_DISABLE_WARNINGS
#if SIMDJSON_COMPETITION_SAX #if SIMDJSON_COMPETITION_SAX
#include "kostya/nlohmann_json_sax.h" #include "kostya/nlohmann_json_sax.h"
#endif // SIMDJSON_COMPETITION_SAX #endif // SIMDJSON_COMPETITION_SAX
#include "kostya/boostjson.h"
#include "large_random/simdjson_ondemand.h" #include "large_random/simdjson_ondemand.h"
#if SIMDJSON_COMPETITION_ONDEMAND_UNORDERED #if SIMDJSON_COMPETITION_ONDEMAND_UNORDERED
@@ -130,6 +140,7 @@ SIMDJSON_POP_DISABLE_WARNINGS
#if SIMDJSON_COMPETITION_SAX #if SIMDJSON_COMPETITION_SAX
#include "large_random/nlohmann_json_sax.h" #include "large_random/nlohmann_json_sax.h"
#endif // SIMDJSON_COMPETITION_SAX #endif // SIMDJSON_COMPETITION_SAX
#include "large_random/boostjson.h"
#include "amazon_cellphones/simdjson_dom.h" #include "amazon_cellphones/simdjson_dom.h"
#include "amazon_cellphones/simdjson_ondemand.h" #include "amazon_cellphones/simdjson_ondemand.h"
-30
View File
@@ -169,22 +169,6 @@ BENCHMARK(parse_gsoc)->Repetitions(10)->ComputeStatistics("max", [](const std::v
})->DisplayAggregatesOnly(true); })->DisplayAggregatesOnly(true);
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
SIMDJSON_PUSH_DISABLE_WARNINGS
SIMDJSON_DISABLE_DEPRECATED_WARNING
static void json_parse(State& state) {
ParsedJson pj;
if (!pj.allocate_capacity(EMPTY_ARRAY.length())) { return; }
for (simdjson_unused auto _ : state) {
auto error = json_parse(EMPTY_ARRAY, pj);
if (error) { return; }
}
}
SIMDJSON_POP_DISABLE_WARNINGS
BENCHMARK(json_parse);
#endif // SIMDJSON_DISABLE_DEPRECATED_API
static void parser_parse_error_code(State& state) { static void parser_parse_error_code(State& state) {
dom::parser parser; dom::parser parser;
if (parser.allocate(EMPTY_ARRAY.length())) { return; } if (parser.allocate(EMPTY_ARRAY.length())) { return; }
@@ -213,20 +197,6 @@ BENCHMARK(parser_parse_exception);
#endif // SIMDJSON_EXCEPTIONS #endif // SIMDJSON_EXCEPTIONS
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
SIMDJSON_PUSH_DISABLE_WARNINGS
SIMDJSON_DISABLE_DEPRECATED_WARNING
static void build_parsed_json(State& state) {
for (simdjson_unused auto _ : state) {
dom::parser parser = simdjson::build_parsed_json(EMPTY_ARRAY);
if (!parser.valid) { return; }
}
}
SIMDJSON_POP_DISABLE_WARNINGS
BENCHMARK(build_parsed_json);
#endif
static void document_parse_error_code(State& state) { static void document_parse_error_code(State& state) {
for (simdjson_unused auto _ : state) { for (simdjson_unused auto _ : state) {
dom::parser parser; dom::parser parser;
+13 -9
View File
@@ -445,7 +445,7 @@ struct benchmarker {
return 100.0 * a / b; return 100.0 * a / b;
} }
void print(bool tabbed_output) const { void print(bool tabbed_output, bool stage1_only) const {
if (tabbed_output) { if (tabbed_output) {
char* filename_copy = reinterpret_cast<char*>(malloc(strlen(filename)+1)); char* filename_copy = reinterpret_cast<char*>(malloc(strlen(filename)+1));
SIMDJSON_PUSH_DISABLE_WARNINGS SIMDJSON_PUSH_DISABLE_WARNINGS
@@ -503,17 +503,21 @@ struct benchmarker {
stats->blocks_with_16_structurals_flipped, percent(stats->blocks_with_16_structurals_flipped, stats->blocks)); stats->blocks_with_16_structurals_flipped, percent(stats->blocks_with_16_structurals_flipped, stats->blocks));
} }
printf("\n"); printf("\n");
printf("All Stages (excluding allocation)\n"); if(!stage1_only) {
print_aggregate("| " , all_stages_without_allocation.best); printf("All Stages (excluding allocation)\n");
// frequently, allocation is a tiny fraction of the running time so we omit it print_aggregate("| " , all_stages_without_allocation.best);
if(allocate_stage.best.elapsed_sec() > 0.01 * all_stages_without_allocation.best.elapsed_sec()) { // frequently, allocation is a tiny fraction of the running time so we omit it
printf("|- Allocation\n"); if(allocate_stage.best.elapsed_sec() > 0.01 * all_stages_without_allocation.best.elapsed_sec()) {
print_aggregate("| ", allocate_stage.best); printf("|- Allocation\n");
print_aggregate("| ", allocate_stage.best);
}
} }
printf("|- Stage 1\n"); printf("|- Stage 1\n");
print_aggregate("| ", stage1.best); print_aggregate("| ", stage1.best);
printf("|- Stage 2\n"); if(!stage1_only) {
print_aggregate("| ", stage2.best); printf("|- Stage 2\n");
print_aggregate("| ", stage2.best);
}
if (collector.has_events()) { if (collector.has_events()) {
double freq1 = (stage1.best.cycles() / stage1.best.elapsed_sec()) / 1000000000.0; double freq1 = (stage1.best.cycles() / stage1.best.elapsed_sec()) / 1000000000.0;
double freq2 = (stage2.best.cycles() / stage2.best.elapsed_sec()) / 1000000000.0; double freq2 = (stage2.best.cycles() / stage2.best.elapsed_sec()) / 1000000000.0;
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#ifdef SIMDJSON_COMPETITION_BOOSTJSON
#include "distinct_user_id.h"
namespace distinct_user_id {
struct boostjson {
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
auto root = boost::json::parse(json);
for (const auto &tweet : root.at("statuses").as_array()) {
result.push_back(tweet.at("user").at("id").to_number<uint64_t>());
if (tweet.as_object().if_contains("retweeted_status")) {
result.push_back(tweet.at("retweeted_status").at("user").at("id").to_number<uint64_t>());
}
}
return true;
}
};
BENCHMARK_TEMPLATE(distinct_user_id, boostjson)->UseManualTime();
} // namespace distinct_user_id
#endif // SIMDJSON_COMPETITION_BOOSTJSON
+1 -1
View File
@@ -218,7 +218,7 @@ int main(int argc, char *argv[]) {
if (!options.verbose) { progress.erase(); } if (!options.verbose) { progress.erase(); }
for (size_t i=0; i<options.files.size(); i++) { for (size_t i=0; i<options.files.size(); i++) {
benchmarkers[i]->print(options.tabbed_output); benchmarkers[i]->print(options.tabbed_output, options.stage1_only);
delete benchmarkers[i]; delete benchmarkers[i];
} }
+28 -3
View File
@@ -34,11 +34,15 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "linux-perf-events.h"
#ifdef __linux__ #ifdef __linux__
#include "linux-perf-events.h"
#include <libgen.h> #include <libgen.h>
#endif #endif
#if __APPLE__ && __aarch64__
#include "apple/apple_arm_events.h"
#endif
#include "simdjson.h" #include "simdjson.h"
using std::string; using std::string;
@@ -134,7 +138,7 @@ struct event_collector {
#if defined(__linux__) #if defined(__linux__)
LinuxEvents<PERF_TYPE_HARDWARE> linux_events; LinuxEvents<PERF_TYPE_HARDWARE> linux_events;
event_collector(simdjson_unused bool quiet = false) : linux_events(vector<int>{ event_collector() : linux_events(vector<int>{
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS #if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
PERF_COUNT_HW_CPU_CYCLES, PERF_COUNT_HW_CPU_CYCLES,
PERF_COUNT_HW_INSTRUCTIONS, PERF_COUNT_HW_INSTRUCTIONS,
@@ -149,8 +153,17 @@ struct event_collector {
bool has_events() { bool has_events() {
return linux_events.is_working(); return linux_events.is_working();
} }
#elif __APPLE__ && __aarch64__
AppleEvents apple_events;
performance_counters diff;
event_collector() : diff(0) {
apple_events.setup_performance_counters();
}
bool has_events() {
return apple_events.setup_performance_counters();
}
#else #else
event_collector(simdjson_unused bool _quiet = false) {} event_collector() {}
bool has_events() { bool has_events() {
return false; return false;
} }
@@ -159,6 +172,8 @@ struct event_collector {
simdjson_inline void start() { simdjson_inline void start() {
#if defined(__linux) #if defined(__linux)
linux_events.start(); linux_events.start();
#elif __APPLE__ && __aarch64__
if(has_events()) { diff = apple_events.get_counters(); }
#endif #endif
start_clock = steady_clock::now(); start_clock = steady_clock::now();
} }
@@ -166,6 +181,16 @@ struct event_collector {
time_point<steady_clock> end_clock = steady_clock::now(); time_point<steady_clock> end_clock = steady_clock::now();
#if defined(__linux) #if defined(__linux)
linux_events.end(count.event_counts); linux_events.end(count.event_counts);
#elif __APPLE__ && __aarch64__
if(has_events()) {
performance_counters end = apple_events.get_counters();
diff = end - diff;
}
count.event_counts[0] = diff.cycles;
count.event_counts[1] = diff.instructions;
count.event_counts[2] = diff.missed_branches;
count.event_counts[3] = 0;
count.event_counts[4] = 0;
#endif #endif
count.elapsed = end_clock - start_clock; count.elapsed = end_clock - start_clock;
return count; return count;
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#ifdef SIMDJSON_COMPETITION_BOOSTJSON
#include "find_tweet.h"
namespace find_tweet {
struct boostjson {
using StringType=std::string;
bool run(simdjson::padded_string &json, uint64_t find_id, std::string &result) {
auto root = boost::json::parse(json);
for (const auto &tweet : root.at("statuses").as_array()) {
if (tweet.at("id") == find_id) {
result = tweet.at("text").as_string();
return true;
}
}
return false;
}
};
BENCHMARK_TEMPLATE(find_tweet, boostjson)->UseManualTime();
} // namespace find_tweet
#endif // SIMDJSON_COMPETITION_BOOSTJSON
+104
View File
@@ -0,0 +1,104 @@
#pragma once
#ifdef SIMDJSON_COMPETITION_BOOSTJSON
#include "json2msgpack.h"
namespace json2msgpack {
struct boostjson2msgpack {
inline std::string_view to_msgpack(const boost::json::value &root, uint8_t *buf) {
buff = buf;
recursive_processor(root);
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
}
private:
uint8_t *buff{};
inline void write_double(const double d) noexcept {
*buff++ = 0xcb;
::memcpy(buff, &d, sizeof(d));
buff += sizeof(d);
}
inline void write_byte(const uint8_t b) noexcept {
*buff = b;
buff++;
}
inline void write_uint32(const uint32_t w) noexcept {
::memcpy(buff, &w, sizeof(w));
buff += sizeof(w);
}
inline void write_string(const std::string & str) {
write_byte(0xdb);
write_uint32(uint32_t(str.size()));
::memcpy(buff, str.data(), str.size());
buff += str.size();
}
inline void recursive_processor(const boost::json::value &element) {
switch(element.kind()) {
case boost::json::kind::array: {
write_byte(0xdd);
const auto &array = element.as_array();
write_uint32(static_cast<uint32_t>(array.size()));
for (const auto &child : array) {
recursive_processor(child);
}
} break;
case boost::json::kind::object: {
write_byte(0xdf);
const auto &object = element.as_object();
write_uint32(static_cast<uint32_t>(object.size()));
for (const auto &child : object) {
write_string(child.key_c_str());
recursive_processor(child.value());
}
} break;
case boost::json::kind::int64:
case boost::json::kind::uint64:
case boost::json::kind::double_:
write_double(element.to_number<double>());
break;
case boost::json::kind::string:
write_string(element.as_string().c_str());
break;
case boost::json::kind::bool_:
write_byte(0xc2 + element.as_bool());
break;
case boost::json::kind::null:
write_byte(0xc0);
break;
default:
printf("unexpected\n");
break;
}
}
};
struct boostjson {
using StringType=std::string;
boostjson2msgpack parser{};
bool run(simdjson::padded_string &json, char *buffer, std::string_view &result) {
auto root = boost::json::parse(json);
result = parser.to_msgpack(root, reinterpret_cast<uint8_t *>(buffer));
return true;
}
};
BENCHMARK_TEMPLATE(json2msgpack, boostjson)->UseManualTime();
} // namespace json2msgpack
#endif // SIMDJSON_COMPETITION_BOOSTJSON
+1 -1
View File
@@ -15,7 +15,7 @@ struct simdjsondom2msgpack {
* @param json JSON input * @param json JSON input
* @param buf temporary buffer (must be large enough, with simdjson::SIMDJSON_PADDING bytes * @param buf temporary buffer (must be large enough, with simdjson::SIMDJSON_PADDING bytes
* of padding) * of padding)
* @return std::string_view msgpack output, writting to the temporary buffer * @return std::string_view msgpack output, writing to the temporary buffer
*/ */
inline std::string_view to_msgpack(const simdjson::padded_string &json, inline std::string_view to_msgpack(const simdjson::padded_string &json,
uint8_t *buf); uint8_t *buf);
+1 -1
View File
@@ -36,7 +36,7 @@ struct simdjson2msgpack {
* @param json JSON input * @param json JSON input
* @param buf temporary buffer (must be large enough, with simdjson::SIMDJSON_PADDING bytes * @param buf temporary buffer (must be large enough, with simdjson::SIMDJSON_PADDING bytes
* of padding) * of padding)
* @return std::string_view msgpack output, writting to the temporary buffer * @return std::string_view msgpack output, writing to the temporary buffer
*/ */
inline std::string_view to_msgpack(const simdjson::padded_string &json, inline std::string_view to_msgpack(const simdjson::padded_string &json,
uint8_t *buf); uint8_t *buf);
+1 -1
View File
@@ -24,7 +24,7 @@ struct file_runner : public runner_base<I> {
simdjson_warn_unused bool before_run(benchmark::State &state) { simdjson_warn_unused bool before_run(benchmark::State &state) {
if (!runner_base<I>::after_run(state)) { return false; }; if (!runner_base<I>::after_run(state)) { return false; };
// Copy the original json in case we did *in situ* last time // Copy the original JSON in case we did *in situ* last time
std::memcpy(json.data(), original_json.data(), original_json.size()); std::memcpy(json.data(), original_json.data(), original_json.size());
return true; return true;
} }
@@ -19,7 +19,7 @@ void maybe_display_implementation() {
template<typename B, typename R> static void run_json_benchmark(benchmark::State &state) { template<typename B, typename R> static void run_json_benchmark(benchmark::State &state) {
maybe_display_implementation(); maybe_display_implementation();
event_collector collector(true); event_collector collector;
event_aggregate events; event_aggregate events;
// Warmup and equality check (make sure the data is right!) // Warmup and equality check (make sure the data is right!)
+1 -1
View File
@@ -13,7 +13,7 @@ struct string_runner : public runner_base<I> {
simdjson_warn_unused bool before_run(benchmark::State &state) { simdjson_warn_unused bool before_run(benchmark::State &state) {
if (!runner_base<I>::after_run(state)) { return false; }; if (!runner_base<I>::after_run(state)) { return false; };
// Copy the original json in case we did *in situ* // Copy the original JSON in case we did *in situ*
std::memcpy(json.data(), original_json.data(), original_json.size()); std::memcpy(json.data(), original_json.data(), original_json.size());
return true; return true;
} }
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#ifdef SIMDJSON_COMPETITION_BOOSTJSON
#include "kostya.h"
namespace kostya {
struct boostjson {
static constexpr diff_flags DiffFlags = diff_flags::IMPRECISE_FLOATS;
bool run(simdjson::padded_string &json, std::vector<point> &result) {
auto root = boost::json::parse(json);
for (const auto &point : root.at("coordinates").as_array()) {
result.emplace_back(json_benchmark::point{
point.at("x").to_number<double>(),
point.at("y").to_number<double>(),
point.at("z").to_number<double>()
});
}
return true;
}
};
BENCHMARK_TEMPLATE(kostya, boostjson)->UseManualTime();
} // namespace kostya
#endif // SIMDJSON_COMPETITION_BOOSTJSON
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#ifdef SIMDJSON_COMPETITION_BOOSTJSON
#include "large_random.h"
namespace large_random {
struct boostjson {
static constexpr diff_flags DiffFlags = diff_flags::IMPRECISE_FLOATS;
bool run(simdjson::padded_string &json, std::vector<point> &result) {
auto root = boost::json::parse(json);
for (const auto &point : root.as_array()) {
result.emplace_back(json_benchmark::point{
point.at("x").to_number<double>(),
point.at("y").to_number<double>(),
point.at("z").to_number<double>()
});
}
return true;
}
};
BENCHMARK_TEMPLATE(large_random, boostjson)->UseManualTime();
} // namespace large_random
#endif // SIMDJSON_COMPETITION_BOOSTJSON
+43
View File
@@ -0,0 +1,43 @@
#pragma once
#ifdef SIMDJSON_COMPETITION_BOOSTJSON
#include "partial_tweets.h"
namespace partial_tweets {
struct boostjson {
using StringType=std::string;
bool run(simdjson::padded_string &json, std::vector<tweet<StringType>> &result) {
auto root = boost::json::parse(json);
for (const auto &tweet : root.at("statuses").as_array()) {
const auto &user = tweet.at("user");
auto in_reply_to_status_id = tweet.as_object().if_contains("in_reply_to_status_id")
? tweet.at("in_reply_to_status_id") : boost::json::value();
result.emplace_back(partial_tweets::tweet<StringType>{
tweet.at("created_at").as_string().c_str(),
tweet.at("id").to_number<uint64_t>(),
tweet.at("text").as_string().c_str(),
in_reply_to_status_id.is_null() ? 0 : in_reply_to_status_id.to_number<uint64_t>(),
{
user.at("id").to_number<uint64_t>(),
user.at("screen_name").as_string().c_str()
},
tweet.at("retweet_count").to_number<uint64_t>(),
tweet.at("favorite_count").to_number<uint64_t>()
});
}
return true;
}
};
BENCHMARK_TEMPLATE(partial_tweets, boostjson)->UseManualTime();
} // namespace partial_tweets
#endif // SIMDJSON_COMPETITION_BOOSTJSON
+37
View File
@@ -0,0 +1,37 @@
#pragma once
#if SIMDJSON_COMPETITION_BOOSTJSON
#include "top_tweet.h"
namespace top_tweet {
using namespace simdjson;
struct boostjson {
using StringType=std::string;
bool run(simdjson::padded_string &json, int64_t max_retweet_count, top_tweet_result<StringType> &result) {
result.retweet_count = -1;
boost::json::value top_tweet{};
auto root = boost::json::parse(json);
for (const auto &tweet : root.at("statuses").as_array()) {
int64_t retweet_count = tweet.at("retweet_count").as_int64();
if (retweet_count <= max_retweet_count && retweet_count >= result.retweet_count) {
result.retweet_count = retweet_count;
top_tweet = tweet;
}
}
result.text = top_tweet.at("text").as_string();
result.screen_name = top_tweet.at("user").at("screen_name").as_string();
return result.retweet_count != -1;
}
};
BENCHMARK_TEMPLATE(top_tweet, boostjson)->UseManualTime();
} // namespace top_tweet
#endif // SIMDJSON_COMPETITION_BOOSTJSON
+5 -1
View File
@@ -114,10 +114,14 @@ set(SIMDJSON_CXX_STANDARD 17 CACHE STRING "the C++ standard to use for simdjson"
set(CMAKE_CXX_STANDARD ${SIMDJSON_CXX_STANDARD}) set(CMAKE_CXX_STANDARD ${SIMDJSON_CXX_STANDARD})
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_MACOSX_RPATH OFF)
set(CMAKE_THREAD_PREFER_PTHREAD ON) set(CMAKE_THREAD_PREFER_PTHREAD ON)
set(THREADS_PREFER_PTHREAD_FLAG ON) set(THREADS_PREFER_PTHREAD_FLAG ON)
set(SIMDJSON_STRUCTURAL_INDEXER_STEP CACHE STRING "the SIMDJSON_STRUCTURAL_INDEXER_STEP variable")
if(SIMDJSON_STRUCTURAL_INDEXER_STEP)
message(STATUS "Setting SIMDJSON_STRUCTURAL_INDEXER_STEP to ${SIMDJSON_STRUCTURAL_INDEXER_STEP}.")
add_compile_definitions(SIMDJSON_STRUCTURAL_INDEXER_STEP=${SIMDJSON_STRUCTURAL_INDEXER_STEP})
endif()
# LTO seems to create all sorts of fun problems. Let us # LTO seems to create all sorts of fun problems. Let us
# disable temporarily. # disable temporarily.
#include(CheckIPOSupported) #include(CheckIPOSupported)
+1
View File
@@ -4,3 +4,4 @@ if("@SIMDJSON_ENABLE_THREADS@")
endif() endif()
include("${CMAKE_CURRENT_LIST_DIR}/simdjsonTargets.cmake") include("${CMAKE_CURRENT_LIST_DIR}/simdjsonTargets.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/simdjson_staticTargets.cmake" OPTIONAL)
+5 -1
View File
@@ -104,7 +104,11 @@ int main() {}
target_compile_definitions(rapidjson INTERFACE RAPIDJSON_HAS_STDSTRING) target_compile_definitions(rapidjson INTERFACE RAPIDJSON_HAS_STDSTRING)
target_include_directories(rapidjson SYSTEM INTERFACE target_include_directories(rapidjson SYSTEM INTERFACE
"${rapidjson_SOURCE_DIR}/include") "${rapidjson_SOURCE_DIR}/include")
target_compile_definitions(rapidjson INTERFACE SIMDJSON_COMPETITION_RAPIDJSON) if (CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 14)
message(STATUS "Disabling rapidjson")
else()
target_compile_definitions(rapidjson INTERFACE SIMDJSON_COMPETITION_RAPIDJSON)
endif()
import_dependency(sajson chadaustin/sajson 2dcfd35) import_dependency(sajson chadaustin/sajson 2dcfd35)
add_library(sajson INTERFACE) add_library(sajson INTERFACE)
+619 -61
View File
@@ -15,9 +15,11 @@ An overview of what you need to know to use simdjson, with examples.
- [string_view](#string_view) - [string_view](#string_view)
- [Using the Parsed JSON](#using-the-parsed-json) - [Using the Parsed JSON](#using-the-parsed-json)
- [Using the Parsed JSON: Additional examples](#using-the-parsed-json-additional-examples) - [Using the Parsed JSON: Additional examples](#using-the-parsed-json-additional-examples)
- [Adding support for custom types](#adding-support-for-custom-types)
- [Minifying JSON strings without parsing](#minifying-json-strings-without-parsing) - [Minifying JSON strings without parsing](#minifying-json-strings-without-parsing)
- [UTF-8 validation (alone)](#utf-8-validation-alone) - [UTF-8 validation (alone)](#utf-8-validation-alone)
- [JSON Pointer](#json-pointer) - [JSON Pointer](#json-pointer)
- [JSONPath](#json-path)
- [Error Handling](#error-handling) - [Error Handling](#error-handling)
- [Error Handling Examples without Exceptions](#error-handling-examples-without-exceptions) - [Error Handling Examples without Exceptions](#error-handling-examples-without-exceptions)
- [Disabling Exceptions](#disabling-exceptions) - [Disabling Exceptions](#disabling-exceptions)
@@ -28,13 +30,15 @@ An overview of what you need to know to use simdjson, with examples.
- [Newline-Delimited JSON (ndjson) and JSON lines](#newline-delimited-json-ndjson-and-json-lines) - [Newline-Delimited JSON (ndjson) and JSON lines](#newline-delimited-json-ndjson-and-json-lines)
- [Parsing Numbers Inside Strings](#parsing-numbers-inside-strings) - [Parsing Numbers Inside Strings](#parsing-numbers-inside-strings)
- [Dynamic Number Types](#dynamic-number-types) - [Dynamic Number Types](#dynamic-number-types)
- [Raw Strings](#raw-strings) - [Raw Strings From Keys](#raw-strings-from-keys)
- [General Direct Access to the Raw JSON String](#general-direct-access-to-the-raw-json-string) - [General Direct Access to the Raw JSON String](#general-direct-access-to-the-raw-json-string)
- [Storing Directly into an Existing String Instance](#storing-directly-into-an-existing-string-instance)
- [Thread Safety](#thread-safety) - [Thread Safety](#thread-safety)
- [Standard Compliance](#standard-compliance) - [Standard Compliance](#standard-compliance)
- [Backwards Compatibility](#backwards-compatibility) - [Backwards Compatibility](#backwards-compatibility)
- [Examples](#examples) - [Examples](#examples)
- [Performance Tips](#performance-tips) - [Performance Tips](#performance-tips)
- [Further Reading](#further-reading)
Requirements Requirements
@@ -67,7 +71,7 @@ c++ myproject.cpp simdjson.cpp
Note: Note:
- Users on macOS and other platforms where default compilers do not provide C++11 compliant by default should request it with the appropriate flag (e.g., `c++ -std=c++11 myproject.cpp simdjson.cpp`). - Users on macOS and other platforms where default compilers do not provide C++11 compliant by default should request it with the appropriate flag (e.g., `c++ -std=c++11 myproject.cpp simdjson.cpp`).
- The library relies on [runtime CPU detection](implementation-selection.md): avoid specifying an architecture at compile time (e.g., `-march-native`). - The library relies on [runtime CPU detection](implementation-selection.md): avoid specifying an architecture at compile time (e.g., `-march-native`) if you want your binaries to run everywhere.
Using simdjson with package managers Using simdjson with package managers
------------------ ------------------
@@ -85,7 +89,7 @@ include(FetchContent)
FetchContent_Declare( FetchContent_Declare(
simdjson simdjson
GIT_REPOSITORY https://github.com/simdjson/simdjson.git GIT_REPOSITORY https://github.com/simdjson/simdjson.git
GIT_TAG tags/v0.9.6 GIT_TAG tags/v3.6.0
GIT_SHALLOW TRUE) GIT_SHALLOW TRUE)
FetchContent_MakeAvailable(simdjson) FetchContent_MakeAvailable(simdjson)
@@ -179,8 +183,8 @@ strcpy(json, "[1]");
ondemand::document doc = parser.iterate(json, strlen(json), sizeof(json)); ondemand::document doc = parser.iterate(json, strlen(json), sizeof(json));
``` ```
The simdjson library will also accept `std::string` instances, as long as the `capacity()` of The simdjson library will also accept `std::string` instances. If the provided
the string exceeds the `size()` by at least `SIMDJSON_PADDING`. You can increase the `capacity()` with the `reserve()` function of your strings. reference is non-const, it will allocate padding as needed.
You can copy your data directly on a `simdjson::padded_string` as follows: You can copy your data directly on a `simdjson::padded_string` as follows:
@@ -218,7 +222,8 @@ This means that while you iterate an array, or search for a field in an object,
walking through the original JSON text, merrily reading commas and colons and brackets to make sure walking through the original JSON text, merrily reading commas and colons and brackets to make sure
you get where you are going. This is the key to On Demand's performance: since it's just an iterator, you get where you are going. This is the key to On Demand's performance: since it's just an iterator,
it lets you parse values as you use them. And particularly, it lets you *skip* values you do not want it lets you parse values as you use them. And particularly, it lets you *skip* values you do not want
to use. to use. On Demand is also ideally suited when you want to capture part of the document without parsing it
immediately (e.g., see [General Direct Access to the Raw JSON String](#general-direct-access-to-the-raw-json-string)).
We refer to "On Demand" as a front-end component since it is an interface between the We refer to "On Demand" as a front-end component since it is an interface between the
low-level parsing functions and the user. It hides much of the complexity of parsing JSON low-level parsing functions and the user. It hides much of the complexity of parsing JSON
@@ -253,7 +258,8 @@ copy the data into their own favorite class instances (e.g., alternatives to `st
A `std::string_view` instance is effectively just a pointer to a region in memory representing A `std::string_view` instance is effectively just a pointer to a region in memory representing
a string. In simdjson, we return `std::string_view` instances that either point within the a string. In simdjson, we return `std::string_view` instances that either point within the
input string you parsed, or to a temporary string buffer inside our parser class instances. input string you parsed (see [General Direct Access to the Raw JSON String](#general-direct-access-to-the-raw-json-string)), or to a temporary string buffer inside
our parser class instances that is valid until the parser object is destroyed or you use it to parse another document.
When using `std::string_view` instances, it is your responsibility to ensure that When using `std::string_view` instances, it is your responsibility to ensure that
`std::string_view` instance does not outlive the pointed-to memory (e.g., either the input `std::string_view` instance does not outlive the pointed-to memory (e.g., either the input
buffer or the parser instance). Furthermore, some operations reset the string buffer buffer or the parser instance). Furthermore, some operations reset the string buffer
@@ -261,6 +267,7 @@ inside our parser instances: e.g., when we parse a new document. Thus a `std::st
is often best viewed as a temporary string value that is tied to the document you are parsing. is often best viewed as a temporary string value that is tied to the document you are parsing.
At the cost of some memory allocation, you may convert your `std::string_view` instances for long-term storage into `std::string` instances: At the cost of some memory allocation, you may convert your `std::string_view` instances for long-term storage into `std::string` instances:
`std::string mycopy(view)` (C++17) or `std::string mycopy(view.begin(), view.end())` (prior to C++17). `std::string mycopy(view)` (C++17) or `std::string mycopy(view.begin(), view.end())` (prior to C++17).
For convenience, we also allow [storing an escaped string directly into an existing string instance](#storing-directly-into-an-existing-string-instance).
The `std::string_view` class has become standard as part of C++17 but it is not always available The `std::string_view` class has become standard as part of C++17 but it is not always available
on compilers which only supports C++11. When we detect that `string_view` is natively on compilers which only supports C++11. When we detect that `string_view` is natively
@@ -335,8 +342,8 @@ support for users who avoid exceptions. See [the simdjson error handling documen
`double(element)`. This works for `std::string_view`, double, uint64_t, int64_t, bool, `double(element)`. This works for `std::string_view`, double, uint64_t, int64_t, bool,
ondemand::object and ondemand::array. We also have explicit methods such as `get_string()`, `get_double()`, ondemand::object and ondemand::array. We also have explicit methods such as `get_string()`, `get_double()`,
`get_uint64()`, `get_int64()`, `get_bool()`, `get_object()` and `get_array()`. After a cast or an explicit method, `get_uint64()`, `get_int64()`, `get_bool()`, `get_object()` and `get_array()`. After a cast or an explicit method,
the number, string or boolean will be parsed, or the initial `{` or `[` will be verified for ondemand::object and ondemand::array. An exception is thrown if the number, string or boolean will be parsed, or the initial `{` or `[` will be verified for `ondemand::object` and `ondemand::array`. An exception may be thrown if
the cast is not possible. Importantly, when getting an ondemand::object or ondemand::array instance, its content is the cast is not possible: there error code is `simdjson::INCORRECT_TYPE` (see [Error Handling](#error-handling)). Importantly, when getting an ondemand::object or ondemand::array instance, its content is
not validated: you are only guaranteed that the corresponding initial character (`{` or `[`) is present. Thus, not validated: you are only guaranteed that the corresponding initial character (`{` or `[`) is present. Thus,
for example, you could have an ondemand::object instance pointing at the invalid JSON `{ "this is not a valid object" }`: the validation occurs as you access the content. for example, you could have an ondemand::object instance pointing at the invalid JSON `{ "this is not a valid object" }`: the validation occurs as you access the content.
The `get_string()` returns a valid UTF-8 string, after The `get_string()` returns a valid UTF-8 string, after
@@ -354,8 +361,8 @@ support for users who avoid exceptions. See [the simdjson error handling documen
> `get_string()` twice on an object (or to cast an object twice to `std::string_view`). > `get_string()` twice on an object (or to cast an object twice to `std::string_view`).
* **Field Access:** To get the value of the "foo" field in an object, use `object["foo"]`. This will * **Field Access:** To get the value of the "foo" field in an object, use `object["foo"]`. This will
scan through the object looking for the field with the matching string, doing a character-by-character scan through the object looking for the field with the matching string, doing a character-by-character
comparison. For efficiency reason, you should avoid looking up the same field repeatedly: e.g., do comparison. It may generate the error `simdjson::NO_SUCH_FIELD` if there is no such key in the object, it may throw an exception (see [Error Handling](#error-handling)). For efficiency reason, you should avoid looking up the same field repeatedly: e.g., do
not do `object["foo"]` followed by `object["foo"]` with the same `object` instance. Keep in mind that On Demand does not buffer or save the result of the parsing: if you repeatedly access `object["foo"]`, then it must repeatedly seek the key and parse the content. The library does not provide a distinct function to check if a key is present, instead we recommend you attempt to access the key: e.g., by doing `ondemand::value val{}; if(!object["foo"].get(val)) {...}`, you have that `val` contains the requested value inside the if clause. It is your responsability as a user to temporarily keep a reference to the value (`auto v = object["foo"]`), or to consume the content and store it in your own data structures. If you consume an not do `object["foo"]` followed by `object["foo"]` with the same `object` instance. For best performance, you should try to query the keys in the same order they appear in the document. If you need several keys and you cannot predict the order they will appear in, it is recommended to iterate through all keys `for(auto field : object) {...}`. Keep in mind that On Demand does not buffer or save the result of the parsing: if you repeatedly access `object["foo"]`, then it must repeatedly seek the key and parse the content. The library does not provide a distinct function to check if a key is present, instead we recommend you attempt to access the key: e.g., by doing `ondemand::value val{}; if (!object["foo"].get(val)) {...}`, you have that `val` contains the requested value inside the if clause. It is your responsibility as a user to temporarily keep a reference to the value (`auto v = object["foo"]`), or to consume the content and store it in your own data structures. If you consume an
object twice: `std::string_view(object["foo"]` followed by `std::string_view(object["foo"]` then your code object twice: `std::string_view(object["foo"]` followed by `std::string_view(object["foo"]` then your code
is in error. Furthermore, you can only consume one field at a time, on the same object. The is in error. Furthermore, you can only consume one field at a time, on the same object. The
value instance you get from `content["bids"]` becomes invalid when you call `content["asks"]`. value instance you get from `content["bids"]` becomes invalid when you call `content["asks"]`.
@@ -370,7 +377,11 @@ support for users who avoid exceptions. See [the simdjson error handling documen
> as a key, it will not be recognized. This is not generally a problem. Nevertheless, if you do need > as a key, it will not be recognized. This is not generally a problem. Nevertheless, if you do need
> to support escaped keys, the method `unescaped_key()` provides the desired unescaped keys by > to support escaped keys, the method `unescaped_key()` provides the desired unescaped keys by
> parsing and writing out the unescaped keys to a string buffer and returning a `std::string_view` > parsing and writing out the unescaped keys to a string buffer and returning a `std::string_view`
> instance. You should expect a performance penalty when using `unescaped_key()`. > instance. The `unescaped_key` takes an optional Boolean value: passing it true will decode invalid
> Unicode sequences with replacement, meaning that the decoding always succeeds but bogus Unicode
> replacement characters are inserted. In general, you should expect a performance penalty
> when using `unescaped_key()` compared to `key()` because of the string processing: the `key()`
> function just points inside the source JSON document.
> >
> ```c++ > ```c++
> auto json = R"({"k\u0065y": 1})"_padded; > auto json = R"({"k\u0065y": 1})"_padded;
@@ -381,7 +392,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
> // parses and writes out the key, after unescaping it, > // parses and writes out the key, after unescaping it,
> // to a string buffer. It causes a performance penalty. > // to a string buffer. It causes a performance penalty.
> std::string_view keyv = field.unescaped_key(); > std::string_view keyv = field.unescaped_key();
> if(keyv == "key") { std::cout << uint64_t(field.value()); } > if (keyv == "key") { std::cout << uint64_t(field.value()); }
> } > }
> ``` > ```
> >
@@ -414,8 +425,10 @@ support for users who avoid exceptions. See [the simdjson error handling documen
step through each value in the JSON array. step through each value in the JSON array.
If you know the type of the value, you can cast it right there, too! `for (double value : array) { ... }`. If you know the type of the value, you can cast it right there, too! `for (double value : array) { ... }`.
* **Object Iteration:** You can iterate through an object's fields, as well: `for (auto field : object) { ... }`
- `field.unescaped_key()` will get you the unescaped key string. You may also use explicit iterators: `for(auto i = array.begin(); i != array.end(); i++) {}`. You can check that an array is empty with the condition `auto i = array.begin(); if (i == array.end()) {...}`.
* **Object Iteration:** You can iterate through an object's fields, as well: `for (auto field : object) { ... }`. You may also use explicit iterators : `for(auto i = object.begin(); i != object.end(); i++) { auto field = *i; .... }`. You can check that an object is empty with the condition `auto i = object.begin(); if (i == object.end()) {...}`.
- `field.unescaped_key()` will get you the unescaped key string. E.g., the JSON string `"\u00e1"` becomes the Unicode string `á`. Optionally, you pass `true` as a parameter to the `unescaped_key` method if you want invalid escape sequences to be replaced by a default replacement character (e.g., `\ud800\ud801\ud811`): otherwise bad escape sequences lead to an immediate error.
- `field.value()` will get you the value, which you can then use all these other methods on. - `field.value()` will get you the value, which you can then use all these other methods on.
* **Array Index:** Because it is forward-only, you cannot look up an array element by index by index. Instead, * **Array Index:** Because it is forward-only, you cannot look up an array element by index by index. Instead,
you should iterate through the array and keep an index yourself. you should iterate through the array and keep an index yourself.
@@ -445,7 +458,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
> { > {
> ondemand::parser parser; > ondemand::parser parser;
> for (ondemand::object car : parser.iterate(cars_json)) { > for (ondemand::object car : parser.iterate(cars_json)) {
> if(uint64_t(car["year"]) > 2000) { > if (uint64_t(car["year"]) > 2000) {
> arrays.push_back(simdjson::to_json_string(car["tire_pressure"])); > arrays.push_back(simdjson::to_json_string(car["tire_pressure"]));
> } > }
> } > }
@@ -454,7 +467,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
> std::ostringstream oss; > std::ostringstream oss;
> oss << "["; > oss << "[";
> for(size_t i = 0; i < arrays.size(); i++) { > for(size_t i = 0; i < arrays.size(); i++) {
> if(i>0) { oss << ","; } > if (i>0) { oss << ","; }
> oss << arrays[i]; > oss << arrays[i];
> } > }
> oss << "]"; > oss << "]";
@@ -535,9 +548,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
* **Tree Walking and JSON Element Types:** Sometimes you don't necessarily have a document * **Tree Walking and JSON Element Types:** Sometimes you don't necessarily have a document
with a known type, and are trying to generically inspect or walk over JSON elements. with a known type, and are trying to generically inspect or walk over JSON elements.
You can also represent arbitrary JSON values with You can also represent arbitrary JSON values with
`ondemand::value` instances: it can represent anything except a scalar document (lone number, string, null or Boolean). You can check for scalar documents with the method `scalar()`. `ondemand::value` instances: it can represent anything except a scalar document (lone number, string, null or Boolean). You can check for scalar documents with the method `scalar()`. You can cast a document that is either an array or an object to an `ondemand::value` instance immediately after you create the document instance: you cannot create a `ondemand::value` instance from a document that has already been accessed as it would mean that you would have two instances of the object or array simultaneously (see [rewinding](#rewinding)). You can query the type of a document or a value with the `type()` method. The `type()` method does not consume or validate documents and values, but it tells you whether they are
You can query the type of a document or a value with the `type()` method.
The `type()` method does not consume or validate documents and values, but it tells you whether they are
- arrays (`json_type::array`), - arrays (`json_type::array`),
- objects (`json_type::object`) - objects (`json_type::object`)
- numbers (`json_type::number`), - numbers (`json_type::number`),
@@ -546,7 +557,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
- null (`json_type::null`). - null (`json_type::null`).
You must still validate and consume the values (e.g., call `is_null()`) after calling `type()`. You must still validate and consume the values (e.g., call `is_null()`) after calling `type()`.
You may also access [raw strings](#raw-strings). You may also access [the raw JSON string](#general-direct-access-to-the-raw-json-string).
For example, the following is a quick and dirty recursive function that verbosely prints the JSON document as JSON. This example also illustrates lifecycle requirements: the `document` instance holds the iterator. The document must remain in scope while you are accessing instances of `value`, `object` and `array`. For example, the following is a quick and dirty recursive function that verbosely prints the JSON document as JSON. This example also illustrates lifecycle requirements: the `document` instance holds the iterator. The document must remain in scope while you are accessing instances of `value`, `object` and `array`.
```c++ ```c++
void recursive_print_json(ondemand::value element) { void recursive_print_json(ondemand::value element) {
@@ -597,7 +608,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
case ondemand::json_type::null: case ondemand::json_type::null:
// We check that the value is indeed null // We check that the value is indeed null
// otherwise: an error is thrown. // otherwise: an error is thrown.
if(element.is_null()) { if (element.is_null()) {
cout << "null"; cout << "null";
} }
break; break;
@@ -730,6 +741,289 @@ for (ondemand::object points : parser.iterate(points_json)) {
} }
``` ```
Adding support for custom types
----------------------
Suppose you have your own types, such as a `Car` struct:
```C++
struct Car {
std::string make;
std::string model;
int64_t year;
std::vector<double> tire_pressure;
};
```
You might want to write code that automatically parses the JSON content to your custom
type:
```C++
padded_string json = R"( [ { "make": "Toyota", "model": "Camry", "year": 2018,
"tire_pressure": [ 40.1, 39.9 ] },
{ "make": "Kia", "model": "Soul", "year": 2012,
"tire_pressure": [ 30.1, 31.0 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999,
"tire_pressure": [ 29.8, 30.0 ] }
])"_padded;
ondemand::parser parser;
ondemand::document doc = parser.iterate(json);
for (auto val : doc) {
Car c(val);
std::cout << c.make << std::endl;
}
```
We may do so by providing additional template definitions to the `ondemand::value` type.
We may start by providing a definition for `std::vector<double>` as follows:
```c++
template <>
simdjson_inline simdjson_result<std::vector<double>>
simdjson::ondemand::value::get() noexcept {
ondemand::array array;
auto error = get_array().get(array);
if (error) { return error; }
std::vector<double> vec;
for (auto v : array) {
double val;
error = v.get_double().get(val);
if (error) { return error; }
vec.push_back(val);
}
return vec;
}
```
We may then provide support for our `Car`` struct:
```C++
template <>
simdjson_inline simdjson_result<Car> simdjson::ondemand::value::get() noexcept {
ondemand::object obj;
auto error = get_object().get(obj);
if (error) { return error; }
Car car;
// Instead of repeatedly obj["something"], we iterate through the object which
// we expect to be faster.
for (auto field : obj) {
raw_json_string key;
error = field.key().get(key);
if (error) { return error; }
if (key == "make") {
error = field.value().get_string(car.make);
if (error) { return error; }
} else if (key == "model") {
error = field.value().get_string(car.model);
if (error) { return error; }
} else if (key == "year") {
error = field.value().get_int64().get(car.year);
if (error) { return error; }
} else if (key == "tire_pressure") {
error = field.value().get<std::vector<double>>().get(car.tire_pressure);
if (auto error) { return error; }
}
}
return car;
}
```
And that is all that is needed! The following code is a complete example:
```c++
#include "simdjson.h"
#include <iostream>
#include <vector>
using namespace simdjson;
/**
* A custom type that we want to parse.
*/
struct Car {
std::string make;
std::string model;
int64_t year;
std::vector<double> tire_pressure;
};
template <>
simdjson_inline simdjson_result<std::vector<double>>
simdjson::ondemand::value::get() noexcept {
ondemand::array array;
auto error = get_array().get(array);
if (error) { return error; }
std::vector<double> vec;
for (auto v : array) {
double val;
error = v.get_double().get(val);
if (error) { return error; }
vec.push_back(val);
}
return vec;
}
template <>
simdjson_inline simdjson_result<Car> simdjson::ondemand::value::get() noexcept {
ondemand::object obj;
auto error = get_object().get(obj);
if (error) { return error; }
Car car;
// Instead of repeatedly obj["something"], we iterate through the object which
// we expect to be faster.
for (auto field : obj) {
raw_json_string key;
error = field.key().get(key);
if (error) { return error; }
if (key == "make") {
error = field.value().get_string(car.make);
if (error) { return error; }
} else if (key == "model") {
error = field.value().get_string(car.model);
if (error) { return error; }
} else if (key == "year") {
error = field.value().get_int64().get(car.year);
if (error) { return error; }
} else if (key == "tire_pressure") {
error = field.value().get<std::vector<double>>().get(car.tire_pressure);
if (error) { return error; }
}
}
return car;
}
int main(void) {
padded_string json = R"( [ { "make": "Toyota", "model": "Camry", "year": 2018,
"tire_pressure": [ 40.1, 39.9 ] },
{ "make": "Kia", "model": "Soul", "year": 2012,
"tire_pressure": [ 30.1, 31.0 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999,
"tire_pressure": [ 29.8, 30.0 ] }
])"_padded;
ondemand::parser parser;
ondemand::document doc = parser.iterate(json);
for (auto val : doc) {
Car c(val);
std::cout << c.make << std::endl;
}
direct();
return EXIT_SUCCESS;
}
```
Observe that we require an explicit cast (`Car c(val)` instead of `for (Car c : doc) {`): it is by design.
If you prefer to avoid exceptions, you may modify the `main` function as follows:
```c++
int main(void) {
padded_string json = R"( [ { "make": "Toyota", "model": "Camry", "year": 2018,
"tire_pressure": [ 40.1, 39.9 ] },
{ "make": "Kia", "model": "Soul", "year": 2012,
"tire_pressure": [ 30.1, 31.0 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999,
"tire_pressure": [ 29.8, 30.0 ] }
])"_padded;
ondemand::parser parser;
ondemand::document doc;
auto error = parser.iterate(json).get(doc);
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
for (auto val : doc) {
Car c;
error = val.get<Car>().get(c);
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
std::cout << c.make << std::endl;
}
return EXIT_SUCCESS;
}
```
Our example is limited to `ondemand::value` instances. If you wish to also be able to map
directly the document instance itself to a custom type, you need to provide the definitions to
the `ondemand::document` type. In this instance, we must replace the function with signature
`simdjson_result<Car> simdjson::ondemand::value::get()` with a function having signature
`simdjson_result<Car> simdjson::ondemand::document::get() &`. The following is a complete
example:
```C++
#include "simdjson.h"
#include <iostream>
#include <vector>
using namespace simdjson;
/**
* A custom type that we want to parse.
*/
struct Car {
std::string make;
std::string model;
int64_t year;
std::vector<double> tire_pressure;
};
template <>
simdjson_inline simdjson_result<std::vector<double>>
simdjson::ondemand::value::get() noexcept {
ondemand::array array;
if (auto error = get_array().get(array); error) { return error; }
std::vector<double> vec;
for (auto v : array) {
double val;
if (auto error = v.get_double().get(val); error) { return error; }
vec.push_back(val);
}
return vec;
}
template <>
simdjson_inline simdjson_result<Car> simdjson::ondemand::document::get() & noexcept {
ondemand::object obj;
auto error = get_object().get(obj);
if (error) {
return error;
}
Car car;
// Instead of repeatedly obj["something"], we iterate through the object which
// we expect to be faster.
for (auto field : obj) {
raw_json_string key;
error = field.key().get(key);
if (error) { return error; }
if (key == "make") {
error = field.value().get_string(car.make);
if (error) { return error; }
} else if (key == "model") {
error = field.value().get_string(car.model);
if (error) { return error; }
} else if (key == "year") {
error = field.value().get_int64().get(car.year);
if (error) { return error; }
} else if (key == "tire_pressure") {
error = field.value().get<std::vector<double>>().get(car.tire_pressure);
if (error) { return error; }
}
}
return car;
}
int main(void) {
padded_string json = R"( { "make": "Toyota", "model": "Camry", "year": 2018,
"tire_pressure": [ 40.1, 39.9 ] } )"_padded;
ondemand::parser parser;
ondemand::document doc = parser.iterate(json);
Car c(doc);
std::cout << c.make << std::endl;
return EXIT_SUCCESS;
}
```
Minifying JSON strings without parsing Minifying JSON strings without parsing
---------------------- ----------------------
@@ -787,10 +1081,10 @@ auto cars = parser.iterate(cars_json);
cout << cars.at_pointer("/0/tire_pressure/1") << endl; // Prints 39.9 cout << cars.at_pointer("/0/tire_pressure/1") << endl; // Prints 39.9
``` ```
A JSON Path is a sequence of segments each starting with the '/' character. Within arrays, an integer A JSON Pointer path is a sequence of segments each starting with the '/' character. Within arrays, a zero-based integer
index allows you to select the indexed node. Within objects, the string value of the key allows you to index allows you to select the indexed node. Within objects, the string value of the key allows you to
select the value. If your keys contain the characters '/' or '~', they must be escaped as '~1' and select the value. If your keys contain the characters '/' or '~', they must be escaped as '~1' and
'~0' respectively. An empty JSON Path refers to the whole document. '~0' respectively. An empty JSON Pointer Path refers to the whole document.
For multiple JSON pointer queries on a document, one can call `at_pointer` multiple times. For multiple JSON pointer queries on a document, one can call `at_pointer` multiple times.
@@ -811,6 +1105,17 @@ for (size_t i = 0; i < size; i++) {
} }
``` ```
In most instances, a JSON Pointer is an ASCII string and the keys in a JSON document
are ASCII strings. We support UTF-8 in JSON Pointer, but key values are matched exactly, without unescaping or Unicode normalization. We do a byte-by-byte comparison. The e acute character is
considered distinct from its escaped version `\u00E9`. E.g.,
```c++
const padded_string json = "{\"\\u00E9\":123}"_padded;
auto doc = parser.iterate(json);
doc.at_pointer("/\\u00E9") == 123; // true
doc.at_pointer((const char*)u8"/\u00E9") // returns an error (NO_SUCH_FIELD)
```
Note that `at_pointer` calls [`rewind`](#rewind) to reset the parser at the beginning of the document. Hence, it invalidates all previously parsed values, objects and arrays: make sure to consume the values between each call to `at_pointer`. Consider the following example where one wants to store each object from the JSON into a vector of `struct car_type`: Note that `at_pointer` calls [`rewind`](#rewind) to reset the parser at the beginning of the document. Hence, it invalidates all previously parsed values, objects and arrays: make sure to consume the values between each call to `at_pointer`. Consider the following example where one wants to store each object from the JSON into a vector of `struct car_type`:
```c++ ```c++
@@ -870,9 +1175,55 @@ doc.rewind(); // Need to manually rewind to be able to use find_field properly f
std::cout << doc.find_field("k0") << std::endl; // Prints 27 std::cout << doc.find_field("k0") << std::endl; // Prints 27
``` ```
When the JSON path is the empty string (`""`) applied to a scalar document (lone string, number, Boolean or null), a SCALAR_DOCUMENT_AS_VALUE error is returned because scalar document cannot When the JSON Pointer Path is the empty string (`""`) applied to a scalar document (lone string, number, Boolean or null), a SCALAR_DOCUMENT_AS_VALUE error is returned because scalar document cannot
be represented as `value` instances. You can check that a document is a scalar with the method `scalar()`. be represented as `value` instances. You can check that a document is a scalar with the method `scalar()`.
JSONPath
------------
The simdjson library now supports a subset of [JSONPath](https://datatracker.ietf.org/doc/html/draft-normington-jsonpath-00) through the `at_path()` method, allowing you to reach further into the document in a single call. The subset of JSONPath that is implemented is the subset that is trivially convertible into the JSON Pointer format, using `.` to access a field and `[]` to access a specific index.
This implementation relies on `at_path()` converting its argument to JSON Pointer and then calling `at_pointer`, which makes use of [`rewind`](#rewind) to reset the parser at the beginning of the document. Hence, it invalidates all previously parsed values, objects and arrays: make sure to consume the values between each call to `at_path`.
Consider the following example:
```c++
auto cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
ondemand::parser parser;
auto cars = parser.iterate(cars_json);
cout << cars.at_path("[0].tire_pressure[1]") << endl; // Prints 39.9
```
A call to `at_path(json_path)` can result in any of the errors that are returned by the `at_pointer` method and if the conversion of `json_path` to JSON Pointer fails, it will lead to an `simdjson::INVALID_JSON_POINTER`error.
```c++
auto cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
ondemand::parser parser;
auto cars = parser.iterate(cars_json);
ASSERT_ERROR(cars.at_path("[0].tire_presure[1").get(x), INVALID_JSON_POINTER); // Fails on conversion to JSON Pointer, since last square bracket was not properly closed.
ASSERT_ERROR(cars.at_path("[0].incorrect_field[1]").get(x), NO_SUCH_FIELD); // Conversion to JSON Pointer succeeds, but fails on at_pointer() since the path is invalid.
```
In most instances, a JSONPath is an ASCII string and the keys in a JSON document
are ASCII strings. We support UTF-8 within a JSONPath expression, but key values are
matched exactly, without unescaping or Unicode normalization. We do a byte-by-byte comparison.
The e acute character is considered distinct from its escaped version `\u00E9`. E.g.,
```c++
const padded_string json = "{\"\\u00E9\":123}"_padded;
auto doc = parser.iterate(json);
doc.at_path(".\\u00E9") == 123; // true
doc.at_path((const char*)u8".\u00E9") // returns an error (NO_SUCH_FIELD)
```
Error Handling Error Handling
-------------- --------------
@@ -887,10 +1238,17 @@ auto error = parser.iterate(json).get(doc);
if (error) { cerr << error << endl; exit(1); } if (error) { cerr << error << endl; exit(1); }
``` ```
When there is no error, the error code simdjson::SUCCESS is returned: it evaluates as false as a Boolean. When there is no error, the error code `simdjson::SUCCESS`is returned: it evaluates as false as a Boolean.
We have several error codes to indicate errors, they all evaluate to true as a Boolean: your software should not generally not depend on exact We have several error codes to indicate errors, they all evaluate to true as a Boolean: your software should not generally not depend on exact
error codes. We may change the error codes in future releases and the exact error codes could vary depending on your system. error codes. We may change the error codes in future releases and the exact error codes could vary depending on your system.
Some errors are recoverable:
* You may get the error `simdjson::INCORRECT_TYPE` after trying to convert a value to an incorrect type: e.g., you expected a number and try to convert the value to a number, but it is an array.
* You may query a key from an object, but the key is missing in which case you get the error `simdjson::NO_SUCH_FIELD`: e.g., you call `obj["myname"]` and the object does not have a key `"myname"`.
Other errors (e.g., `simdjson::INCOMPLETE_ARRAY_OR_OBJECT`) may indicate a fatal error and often follow from the fact that the document is not valid JSON. In which case, it is no longer possible to continue accessing the document: calling the method `is_alive()` on the document instance returns false. All following accesses will keep returning the same fatal error (e.g., `simdjson::INCOMPLETE_ARRAY_OR_OBJECT`).
When you use the code without exceptions, it is your responsibility to check for error before using the When you use the code without exceptions, it is your responsibility to check for error before using the
result: if there is an error, the result value will not be valid and using it will caused undefined behavior. Most compilers should be able to help you if you activate the right result: if there is an error, the result value will not be valid and using it will caused undefined behavior. Most compilers should be able to help you if you activate the right
set of warnings: they can identify variables that are written to but never otherwise accessed. set of warnings: they can identify variables that are written to but never otherwise accessed.
@@ -903,11 +1261,11 @@ bool simple_error_example() {
ondemand::parser parser; ondemand::parser parser;
auto json = R"({"bad number":3.14.1 })"_padded; auto json = R"({"bad number":3.14.1 })"_padded;
ondemand::document doc; ondemand::document doc;
if( parser.iterate(json).get(doc) != SUCCESS ) { return false; } if (parser.iterate(json).get(doc) != SUCCESS) { return false; }
double x; double x;
auto error = doc["bad number"].get_double().get(x); auto error = doc["bad number"].get_double().get(x);
// returns "simdjson::NUMBER_ERROR" // returns "simdjson::NUMBER_ERROR"
if(error != SUCCESS) { if (error != SUCCESS) {
std::cout << error << std::endl; std::cout << error << std::endl;
return false; return false;
} }
@@ -969,10 +1327,10 @@ it selects the key `"count"` within that object.
int main(void) { int main(void) {
simdjson::ondemand::parser parser; simdjson::ondemand::parser parser;
auto error = padded_string::load("twitter.json").get(json); auto error = padded_string::load("twitter.json").get(json);
if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; } if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
simdjson::ondemand::document tweets; simdjson::ondemand::document tweets;
error = parser.iterate(json).get(tweets); error = parser.iterate(json).get(tweets);
if( error ) { std::cerr << error << std::endl; return EXIT_FAILURE; } if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
simdjson::ondemand::value res; simdjson::ondemand::value res;
error = tweets["search_metadata"]["count"].get(res); error = tweets["search_metadata"]["count"].get(res);
if (error != SUCCESS) { if (error != SUCCESS) {
@@ -1003,12 +1361,12 @@ int main(void) {
simdjson::ondemand::document tweets; simdjson::ondemand::document tweets;
padded_string json; padded_string json;
auto error = padded_string::load("twitter.json").get(json); auto error = padded_string::load("twitter.json").get(json);
if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; } if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
error = parser.iterate(json).get(tweets); error = parser.iterate(json).get(tweets);
if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; } if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
uint64_t identifier; uint64_t identifier;
error = tweets["statuses"].at(0)["id"].get(identifier); error = tweets["statuses"].at(0)["id"].get(identifier);
if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; } if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
std::cout << identifier << std::endl; std::cout << identifier << std::endl;
} }
``` ```
@@ -1032,40 +1390,40 @@ bool parse() {
// Iterating through an array of objects // Iterating through an array of objects
auto error = parser.iterate(cars_json).get(doc); auto error = parser.iterate(cars_json).get(doc);
if(error) { std::cerr << error << std::endl; return false; } if (error) { std::cerr << error << std::endl; return false; }
ondemand::array cars; // invalid until the get() succeeds ondemand::array cars; // invalid until the get() succeeds
error = doc.get_array().get(cars); error = doc.get_array().get(cars);
for (auto car_value : cars) { for (auto car_value : cars) {
ondemand::object car; // invalid until the get() succeeds ondemand::object car; // invalid until the get() succeeds
error = car_value.get_object().get(car); error = car_value.get_object().get(car);
if(error) { std::cerr << error << std::endl; return false; } if (error) { std::cerr << error << std::endl; return false; }
// Accessing a field by name // Accessing a field by name
std::string_view make; std::string_view make;
std::string_view model; std::string_view model;
error = car["make"].get(make); error = car["make"].get(make);
if(error) { std::cerr << error << std::endl; return false; } if (error) { std::cerr << error << std::endl; return false; }
error = car["model"].get(model); error = car["model"].get(model);
if(error) { std::cerr << error << std::endl; return false; } if (error) { std::cerr << error << std::endl; return false; }
cout << "Make/Model: " << make << "/" << model << endl; cout << "Make/Model: " << make << "/" << model << endl;
// Casting a JSON element to an integer // Casting a JSON element to an integer
uint64_t year{}; uint64_t year{};
error = car["year"].get(year); error = car["year"].get(year);
if(error) { std::cerr << error << std::endl; return false; } if (error) { std::cerr << error << std::endl; return false; }
cout << "- This car is " << 2020 - year << " years old." << endl; cout << "- This car is " << 2020 - year << " years old." << endl;
// Iterating through an array of floats // Iterating through an array of floats
double total_tire_pressure = 0; double total_tire_pressure = 0;
ondemand::array pressures; ondemand::array pressures;
error = car["tire_pressure"].get_array().get(pressures); error = car["tire_pressure"].get_array().get(pressures);
if(error) { std::cerr << error << std::endl; return false; } if (error) { std::cerr << error << std::endl; return false; }
for (auto tire_pressure_value : pressures) { for (auto tire_pressure_value : pressures) {
double tire_pressure; double tire_pressure;
error = tire_pressure_value.get_double().get(tire_pressure); error = tire_pressure_value.get_double().get(tire_pressure);
if(error) { std::cerr << error << std::endl; return false; } if (error) { std::cerr << error << std::endl; return false; }
total_tire_pressure += tire_pressure; total_tire_pressure += tire_pressure;
} }
cout << "- Average tire pressure: " << (total_tire_pressure / 4) << endl; cout << "- Average tire pressure: " << (total_tire_pressure / 4) << endl;
@@ -1081,7 +1439,7 @@ after you have initialized them and checked that there is no error:
ondemand::object car; // invalid until the get() succeeds ondemand::object car; // invalid until the get() succeeds
// the `car` instance should not use used before it is initialized // the `car` instance should not use used before it is initialized
error = car_value.get_object().get(car); error = car_value.get_object().get(car);
if(error) { if (error) {
// the `car` instance should not use used // the `car` instance should not use used
} else { } else {
// the `car` instance can be safely used // the `car` instance can be safely used
@@ -1095,20 +1453,20 @@ having to handle exceptions.
ondemand::parser parser; ondemand::parser parser;
ondemand::document doc; ondemand::document doc;
auto error = parser.iterate(json).get(doc); auto error = parser.iterate(json).get(doc);
if(error) { return false; } if (error) { return false; }
ondemand::object object; // invalid until the get() succeeds ondemand::object object; // invalid until the get() succeeds
error = doc.get_object().get(object); error = doc.get_object().get(object);
if(error) { return false; } if (error) { return false; }
for(auto field : object) { for(auto field : object) {
// We could replace 'field.key() with field.unescaped_key(), // We could replace 'field.key() with field.unescaped_key(),
// and ondemand::raw_json_string by std::string_view. // and ondemand::raw_json_string by std::string_view.
ondemand::raw_json_string keyv; ondemand::raw_json_string keyv;
error = field.key().get(keyv); error = field.key().get(keyv);
if(error) { return false; } if (error) { return false; }
if(keyv == "key") { if (keyv == "key") {
uint64_t intvalue; uint64_t intvalue;
error = field.value().get(intvalue); error = field.value().get(intvalue);
if(error) { return false; } if (error) { return false; }
std::cout << intvalue; std::cout << intvalue;
} }
} }
@@ -1287,7 +1645,7 @@ content.
for (uint64_t values : array) { for (uint64_t values : array) {
std::cout << values << std::endl; std::cout << values << std::endl;
} }
if(!doc.at_end()) { if (!doc.at_end()) {
// In this instance, we will be left pointing at 'foo' since we have consumed the array [1,2]. // In this instance, we will be left pointing at 'foo' since we have consumed the array [1,2].
std::cerr << "trailing content at byte index " << doc.current_location() - json.data() << std::endl; std::cerr << "trailing content at byte index " << doc.current_location() - json.data() << std::endl;
} }
@@ -1317,7 +1675,7 @@ before printout the data.
auto doc = parser.iterate(cars_json); auto doc = parser.iterate(cars_json);
for (simdjson_unused ondemand::object car : doc) { for (simdjson_unused ondemand::object car : doc) {
if(car["make"] == "Toyota") { count++; } if (car["make"] == "Toyota") { count++; }
} }
std::cout << "We have " << count << " Toyota cars.\n"; std::cout << "We have " << count << " Toyota cars.\n";
doc.rewind(); // requires simdjson 1.0 or better doc.rewind(); // requires simdjson 1.0 or better
@@ -1385,18 +1743,18 @@ ondemand::parser parser;
ondemand::document_stream stream; ondemand::document_stream stream;
size_t counter{0}; size_t counter{0};
auto error = parser.iterate_many(json, 50).get(stream); auto error = parser.iterate_many(json, 50).get(stream);
if( error ) { /* handle the error */ } if (error) { /* handle the error */ }
for (auto doc: stream) { for (auto doc: stream) {
if(counter < 6) { if (counter < 6) {
int64_t val; int64_t val;
error = doc.at_pointer("/4").get(val); error = doc.at_pointer("/4").get(val);
if( error ) { /* handle the error */ } if (error) { /* handle the error */ }
std::cout << "5 = " << val << std::endl; std::cout << "5 = " << val << std::endl;
} else { } else {
ondemand::value val; ondemand::value val;
error = doc.at_pointer("/4").get(val); error = doc.at_pointer("/4").get(val);
// error == simdjson::CAPACITY // error == simdjson::CAPACITY
if(error) { if (error) {
std::cerr << error << std::endl; std::cerr << error << std::endl;
// We left 293 bytes unprocessed at the tail end of the input. // We left 293 bytes unprocessed at the tail end of the input.
std::cout << " unprocessed bytes at the end: " << stream.truncated_bytes() << std::endl; std::cout << " unprocessed bytes at the end: " << stream.truncated_bytes() << std::endl;
@@ -1422,10 +1780,9 @@ This parser can't support a document that big
If your documents are large (e.g., larger than a megabyte), then the `iterate_many` function is maybe ill-suited. It is really meant to support reading efficiently streams of relatively small documents (e.g., a few kilobytes each). If you have larger documents, you should use other functions like `iterate`. If your documents are large (e.g., larger than a megabyte), then the `iterate_many` function is maybe ill-suited. It is really meant to support reading efficiently streams of relatively small documents (e.g., a few kilobytes each). If you have larger documents, you should use other functions like `iterate`.
We also provide some support for comma-separated documents and other advanced features.
See [iterate_many.md](iterate_many.md) for detailed information and design. See [iterate_many.md](iterate_many.md) for detailed information and design.
Parsing Numbers Inside Strings Parsing Numbers Inside Strings
------------------------------ ------------------------------
@@ -1602,7 +1959,7 @@ It will output:
9999999999999999999 negative: 0 is_integer: 1 large 64-bit integer: 9999999999999999999 large 64-bit integer: 9999999999999999999 9999999999999999999 negative: 0 is_integer: 1 large 64-bit integer: 9999999999999999999 large 64-bit integer: 9999999999999999999
``` ```
Raw Strings Raw Strings From Keys
----------- -----------
It is sometimes useful to have access to a raw (unescaped) string: we make available a It is sometimes useful to have access to a raw (unescaped) string: we make available a
@@ -1638,12 +1995,27 @@ JSON string to a user-provided buffer:
} }
``` ```
Some users might prefer to have a direct access to an `std::string_view` instance
pointing inside the source document. The `key_raw_json_token()` method serves this
purpose. It provides a view on the key, including the starting quote character,
and everything up to the next `:` character after the final quote character. E.g.,
if the key is `"name"` then `key_raw_json_token()` returns an `std::string_view` which
begins with `"name"` and may containing trailing white-space characters.
```C++
auto json = R"( {"name" : "Jack The Ripper \u0033"} )"_padded;
ondemand::parser parser;
ondemand::document doc = parser.iterate(json);
for (auto key_value : doc.get_object()) {
std::string_view keysv = key_value.key_raw_json_token(); // keysv is "\"name\" "
}
```
General Direct Access to the Raw JSON String General Direct Access to the Raw JSON String
-------------------------------- --------------------------------
If your value is a string, the `raw_json_string` gives you direct access to the unprocess If your value is a string, the `raw_json_string` you get with `get_raw_json_string()` gives you direct access to the unprocessed
string. The simdjson library allows you to have access to the raw underlying JSON string. But the simdjson library allows you to have access to the raw underlying JSON
more generally. more generally, not just for strings.
The simdjson library makes explicit assumptions about types. For examples, numbers The simdjson library makes explicit assumptions about types. For examples, numbers
must be integers (up to 64-bit integers) or binary64 floating-point numbers. Some users must be integers (up to 64-bit integers) or binary64 floating-point numbers. Some users
@@ -1676,9 +2048,16 @@ string_view token = obj["value"].raw_json_token();
The `raw_json_token()` should be fast and free of allocation. The `raw_json_token()` should be fast and free of allocation.
If you value is an array or an object, `raw_json_token()` returns effectively a single Given a quote-deliminated string, you find the string sequence inside the quote with a
single line of code:
```C++
std::string_view noquote(std::string_view v) { return {v.data()+1, v.find_last_of('"')-1}; }
```
If your value is an array or an object, `raw_json_token()` returns effectively a single
character (`[`) or (`}`) which is not very useful. For arrays and objects, we have another character (`[`) or (`}`) which is not very useful. For arrays and objects, we have another
method called `raw_json()` which consumes (traverse) the array or the object. method called `raw_json()` which consumes (traverses) the array or the object.
```C++ ```C++
simdjson::ondemand::parser parser; simdjson::ondemand::parser parser;
@@ -1710,6 +2089,82 @@ obj.reset(); // revise the object
uint64_t x = obj["value"]; // gives me 123 uint64_t x = obj["value"]; // gives me 123
``` ```
You can use `raw_json()` with the values inside an array and object. When
calling `raw_json()` on an untyped value, it acts as `raw_json()` when the
value is an array or an object. Otherwise, it acts as `raw_json_token()`.
It is useful if you do not care for the type of the value and just wants a
string representation.
```C++
auto json = R"( [1,2,"fds", {"a":1}, [1,344]] )"_padded;
ondemand::parser parser;
ondemand::document doc = parser.iterate(json);
size_t counter = 0;
for(auto array: doc) {
std::string_view raw = array.raw_json();
// will capture "1", "2", "\"fds\"", "{\"a\":1}", "[1,344]"
}
```
```C++
auto json = R"( {"key1":1,"key2":2,"key3":"fds", "key4":{"a":1}, "key5":[1,344]} )"_padded;
ondemand::parser parser;
ondemand::document doc = parser.iterate(json);
size_t counter = 0;
for(auto key_value: doc.get_object()) {
std::string_view raw = key_value.value().raw_json();
// will capture "1", "2", "\"fds\"", "{\"a\":1}", "[1,344]"
}
```
Storing Directly into an Existing String Instance
-----------------------------------------------------
The simdjson library favours the use of `std::string_view` instances because
it tends to lead to better performance due to causing fewer memory allocations.
However, they are cases where you need to store a string result in an `std::string``
instance. You can do so with a templated version of the `to_string()` method which takes as
a parameter a reference to an `std::string`.
```C++
auto json = R"({
"name": "Daniel",
"age": 42
})"_padded;
ondemand::parser parser;
ondemand::document doc = parser.iterate(json);
std::string name;
doc["name"].get_string(name);
```
The same routine can be written without exceptions handling:
```C++
std::string name;
auto err = doc["name"].get_string(name);
if (err) { /* handle error */ }
```
The `std::string` instance, once created, is independent. Unlike our `std::string_view` instances,
it does not point at data that is within our `parser` instance. The same caveat applies: you should
only consume a JSON string once.
Because `get_string()` is a template that requires a type that can be assigned an `std::string`, you
can use it with features such as `std::optional`:
```C++
auto json = R"({ "foo1": "3.1416" } )"_padded;
ondemand::parser parser;
ondemand::document doc = parser.iterate(json);
std::optional<std::string> value;
if (doc["foo1"].get_string(value)) { /* error */ }
// value was populated with "3.1416"
```
You should be mindful of the trade-off: allocating multiple
`std::string` instances can become expensive.
Thread Safety Thread Safety
------------- -------------
@@ -1938,6 +2393,101 @@ bool example() {
} }
``` ```
* Example 3: CRT
```C++
bool example() {
padded_string padded_input_json = R"([
{ "monitor": [
{ "id": "monitor", "type": "toggle", "label": "monitor" },
{ "id": "profile", "type": "selector", "label": "collection" },
{ "id": "overlay", "type": "selector", "label": "overlay" },
{ "id": "zoom", "type": "toggleSlider", "label": "zoom" }
] },
{ "crt": [
{ "id": "system", "type": "multi", "label": "system", "choices": "PAL, NTSC" },
{ "type": "spacer" },
{ "id": "brightness", "type": "slider", "icon": "brightness" },
{ "id": "contrast", "type": "slider", "icon": "contrast" },
{ "id": "saturation", "type": "slider", "icon": "saturation" },
{ "type": "spacer" },
{ "id": "overscan", "type": "toggleSlider", "label": "overscan" },
{ "type": "spacer" },
{ "id": "emulation", "type": "toggle", "label": "CRT emulation" },
{ "type": "spacer" },
{ "id": "curve", "type": "toggleSlider", "label": "curve" },
{ "id": "bleed", "type": "toggleSlider", "label": "bleed" },
{ "id": "vignette", "type": "toggleSlider", "label": "vignette" },
{ "id": "scanlines", "type": "toggleSlider", "label": "scanlines" },
{ "id": "gridlines", "type": "toggleSlider", "label": "gridlines" },
{ "id": "glow", "type": "toggleSlider", "label": "glow" },
{ "id": "flicker", "type": "toggleSlider", "label": "flicker" },
{ "id": "noise", "type": "toggleSlider", "label": "noise" },
{}
] }
])"_padded;
auto parser = ondemand::parser{};
auto doc = parser.iterate(padded_input_json);
auto root_array = doc.get_array();
// the root should be an object, not an array, but that's the JSON we are
// given.
for (ondemand::object node : root_array) {
// We know that we are going to have just one element in the object.
for (auto field : node) {
std::cout << "\n\ntop level:" << field.key() << std::endl;
// You can get a proper std::string_view for the key with:
// std::string_view key = field.unescaped_key();
// and second for-range loop to get child-elements here
for (ondemand::object inner_object : field.value()) {
auto i = inner_object.begin();
if (i == inner_object.end()) {
std::cout << "empty object" << std::endl;
continue;
} else {
for (; i != inner_object.end(); ++i) {
auto inner_field = *i;
std::cout << '"' << inner_field.key()
<< "\" : " << inner_field.value() << ", ";
// You can get proper std::string_view for the key and value with:
// std::string_view inner_key = field.unescaped_key();
// std::string_view value_str = field.value();
}
}
std::cout << std::endl;
}
// You can break here if you only want just the first element.
// break;
}
}
return true;
}
```
* Example 4: Passing an array to a function
```C++
#include "simdjson.h"
#include <iostream>
// prints the content of the array as hexadecimal 64-bit integers
void f(simdjson::ondemand::array v) {
for(uint64_t val : v) {
std::cout << "0x" << std::hex << val << std::endl;
}
}
int main(void) {
simdjson::padded_string json = R"( [ 897314173811950000, 3122321 ])"_padded;
simdjson::ondemand::parser parser;
simdjson::ondemand::document doc = parser.iterate(json);
f(doc.get_array());
return EXIT_SUCCESS;
}
```
Performance Tips Performance Tips
-------- --------
@@ -1948,6 +2498,8 @@ Performance Tips
- Given a field `field` in an object, calling `field.key()` is often faster than `field.unescaped_key()` so if you do not need an unescaped `std::string_view` instance, prefer `field.key()`. - Given a field `field` in an object, calling `field.key()` is often faster than `field.unescaped_key()` so if you do not need an unescaped `std::string_view` instance, prefer `field.key()`.
- For release builds, we recommend setting `NDEBUG` pre-processor directive when compiling the `simdjson` library. Importantly, using the optimization flags `-O2` or `-O3` under GCC and LLVM clang does not set the `NDEBUG` directive, you must set it manually (e.g., `-DNDEBUG`). - For release builds, we recommend setting `NDEBUG` pre-processor directive when compiling the `simdjson` library. Importantly, using the optimization flags `-O2` or `-O3` under GCC and LLVM clang does not set the `NDEBUG` directive, you must set it manually (e.g., `-DNDEBUG`).
- For long streams of JSON documents, consider [`iterate_many`](iterate_many.md) and [`parse_many`](parse_many.md) for better performance. - For long streams of JSON documents, consider [`iterate_many`](iterate_many.md) and [`parse_many`](parse_many.md) for better performance.
- Never seek to access a field twice (e.g., o["data"] and later again o["data"]). Instead capture once an ondemand::value and reuse it.
- If you must access several different keys in an object, it might be preferable to iterate through all the fields in the object instead, and branch on the field keys.
- If possible, refer to each object and array in your code once. For example, the following code repeatedly refers to the `"data"` key to create an object... - If possible, refer to each object and array in your code once. For example, the following code repeatedly refers to the `"data"` key to create an object...
```C++ ```C++
std::string_view make = o["data"]["make"]; std::string_view make = o["data"]["make"];
@@ -1961,4 +2513,10 @@ Performance Tips
std::string_view year = data["year"]; std::string_view year = data["year"];
std::string_view rating = data["rating"]; std::string_view rating = data["rating"];
``` ```
- To better understand the operation of your On Demand parser, and whether it is performing as well as you think it should be, there is a logger feature built in to simdjson! To use it, define the pre-processor directive `SIMDJSON_VERBOSE_LOGGING` prior to including the `simdjson.h` header, which enables logging in simdjson. Run your code. It may generate a lot of logging output; adding printouts from your application that show each section may be helpful. The logs output will show step-by-step information on state, buffer pointer position, depth, and key retrieval status. The log level is set to `INFO` by default, but can be modified with the environment variable `SIMDJSON_LOG_LEVEL`. Setting the environment variable `SIMDJSON_LOG_LEVEL` to `ERROR` will log only errors. - To better understand the operation of your On Demand parser, and whether it is performing as well as you think it should be, there is a logger feature built in to simdjson! To use it, define the pre-processor directive `SIMDJSON_VERBOSE_LOGGING` prior to including the `simdjson.h` header, which enables logging in simdjson. Run your code. It may generate a lot of logging output; adding printouts from your application that show each section may be helpful. The log's output will show step-by-step information on state, buffer pointer position, depth, and key retrieval status. Importantly, unless `SIMDJSON_VERBOSE_LOGGING` is defined, logging is entirely disabled and thus carries no overhead.
Further reading
--------
- John Keiser, Daniel Lemire, [On-Demand JSON: A Better Way to Parse Documents?](http://arxiv.org/abs/2312.17149), Software: Practice and Experience (to appear)
+6 -6
View File
@@ -105,7 +105,7 @@ Once you have an element, you can navigate it with idiomatic C++ iterators, oper
with the `size()` method. with the `size()` method.
* **Checking an Element Type:** You can check an element's type with `element.type()`. It * **Checking an Element Type:** You can check an element's type with `element.type()`. It
returns an `element_type` with values such as `simdjson::dom::element_type::ARRAY`, `simdjson::dom::element_type::OBJECT`, `simdjson::dom::element_type::INT64`, `simdjson::dom::element_type::UINT64`,`simdjson::dom::element_type::DOUBLE`, `simdjson::dom::element_type::STRING`, `simdjson::dom::element_type::BOOL` or, `simdjson::dom::element_type::NULL_VALUE`. returns an `element_type` with values such as `simdjson::dom::element_type::ARRAY`, `simdjson::dom::element_type::OBJECT`, `simdjson::dom::element_type::INT64`, `simdjson::dom::element_type::UINT64`,`simdjson::dom::element_type::DOUBLE`, `simdjson::dom::element_type::STRING`, `simdjson::dom::element_type::BOOL` or, `simdjson::dom::element_type::NULL_VALUE`.
* **Output to streams and strings:** Given a document or an element (or node) out of a JSON document, you can output a minified string version using the C++ stream idiom (`out << element`). You can also request the construction of a minified string version (`simdjson::minify(element)`). Numbers are serialized as 64-bit floating-point numbers (`double`). * **Output to streams and strings:** Given a document or an element (or node) out of a JSON document, you can output a minified string version using the C++ stream idiom (`out << element`). You can also request the construction of a minified string version (`simdjson::minify(element)`) or a prettified string version (`simdjson::prettify(element)`). Numbers are serialized as 64-bit floating-point numbers (`double`).
### Examples ### Examples
@@ -223,13 +223,13 @@ dom::element cars = parser.parse(cars_json);
cout << cars.at_pointer("/0/tire_pressure/1") << endl; // Prints 39.9 cout << cars.at_pointer("/0/tire_pressure/1") << endl; // Prints 39.9
``` ```
A JSON Path is a sequence of segments each starting with the '/' character. Within arrays, an integer A JSON Pointer expression is a sequence of segments each starting with the '/' character. Within arrays, an integer
index allows you to select the indexed node. Within objects, the string value of the key allows you to index allows you to select the indexed node. Within objects, the string value of the key allows you to
select the value. If your keys contain the characters '/' or '~', they must be escaped as '~1' and select the value. If your keys contain the characters '/' or '~', they must be escaped as '~1' and
'~0' respectively. An empty JSON Path refers to the whole document. '~0' respectively. An empty JSON Pointer expression refers to the whole document.
We also extend the JSON Pointer support to include *relative* paths. We also extend the JSON Pointer support to include *relative* paths.
You can apply a JSON path to any node and the path gets interpreted relatively, as if the current node were a whole JSON document. You can apply a JSON Pointer expression to any node and the path gets interpreted relatively, as if the current node were a whole JSON document.
Consider the following example: Consider the following example:
@@ -329,10 +329,10 @@ int main(void) {
simdjson::dom::parser parser; simdjson::dom::parser parser;
simdjson::dom::element tweets; // invalid until the get() succeeds simdjson::dom::element tweets; // invalid until the get() succeeds
auto error = parser.load("twitter.json").get(tweets); auto error = parser.load("twitter.json").get(tweets);
if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; } if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
uint64_t identifier; uint64_t identifier;
error = tweets["statuses"].at(0)["id"].get(identifier); error = tweets["statuses"].at(0)["id"].get(identifier);
if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; } if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
std::cout << identifier << std::endl; std::cout << identifier << std::endl;
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
+10 -9
View File
@@ -11,22 +11,24 @@ CPU Architecture-Specific Implementations
Overview Overview
-------- --------
The simdjson library takes advantage of SIMD instruction sets such as NEON, SSE and AVX to achieve The simdjson library takes advantage of SIMD instruction sets such as NEON, SSE and AVX to achieve
much of its speed. Because these instruction sets work differently, simdjson has to compile a much of its speed. Because these instruction sets work differently, simdjson has to compile a
different version of the JSON parser for different CPU architectures, often with different different version of the JSON parser for different CPU architectures, often with different
algorithms to take better advantage of a given CPU! algorithms to take better advantage of a given CPU!
The current implementations are: The current implementations are:
* icelake: AVX-512F, AVX-512VBMI, etc. * icelake: AVX-512F, AVX-512_VBMI, AVX-512_VBMI2, AVX-512_DQ, AVX-512512_CD, AVX-512_BW, AVX-512_VL (2019 Intel Ice Lake, Intel Rocket Lake, Intel Sapphire Rapids, AMD Zen 4)
* haswell: AVX2 (2013 Intel Haswell or later) * haswell: AVX2 (2013 Intel Haswell or later, all AMD Zen processors)
* westmere: SSE4.2 (2010 Westmere or later). * westmere: SSE4.2 (2010 Westmere or later).
* arm64: 64-bit ARMv8-A NEON * arm64: 64-bit ARMv8-A NEON
* ppc64: 64-bit POWER8 and POWER9 with VSX and ALTIVEC extensions. Both big endian and little endian are implemented, depends on the compiler you are using. The library is tested on recent, little-endian, POWER systems. * ppc64: 64-bit POWER8 and POWER9 with VSX and ALTIVEC extensions. Both big endian and little endian are implemented, depending on the compiler you are using. The library is tested on recent, little-endian, POWER systems.
* fallback: A generic implementation that runs on any 64-bit processor. * fallback: A generic implementation that runs on any 64-bit processor.
In many cases, you don't know where your compiled binary is going to run, so simdjson automatically In many cases, you don't know where your compiled binary is going to run, so simdjson automatically
compiles *all* the implementations into the executable. On Intel, it will include 4 implementations compiles *all* the implementations into the executable. On Intel, it will include 4 implementations
(icelake, haswell, westmere and fallback), on ARM it will include 2 (arm64 and fallback), and on PPC (icelake, haswell, westmere and fallback), on 64-bit ARM it will include just one since running dispatching is unnecessary, and on PPC
it will include 2 (ppc64 and fallback). it will include 2 (ppc64 and fallback).
If you know more about where you're going to run and want to save the space, you can disable any of If you know more about where you're going to run and want to save the space, you can disable any of
@@ -75,8 +77,7 @@ And look them up by name:
```c++ ```c++
cout << simdjson::get_available_implementations()["fallback"]->description() << endl; cout << simdjson::get_available_implementations()["fallback"]->description() << endl;
``` ```
Though the fallback implementation should always be available, others might be missing. When When an implementation is not available, the bracket call `simdjson::get_available_implementations()[name]`
an implementation is not available, the bracket call `simdjson::get_available_implementations()[name]`
will return the null pointer. will return the null pointer.
The available implementations have been compiled but may not necessarily be run safely on your system The available implementations have been compiled but may not necessarily be run safely on your system
@@ -101,8 +102,8 @@ by comparing it with the null pointer.
```c++ ```c++
auto my_implementation = simdjson::get_available_implementations()["haswell"]; auto my_implementation = simdjson::get_available_implementations()["haswell"];
if(! my_implementation) { exit(1); } if (! my_implementation) { exit(1); }
if(! my_implementation->supported_by_runtime_system()) { exit(1); } if (! my_implementation->supported_by_runtime_system()) { exit(1); }
simdjson::get_active_implementation() = my_implementation; simdjson::get_active_implementation() = my_implementation;
``` ```
@@ -113,7 +114,7 @@ You should call `supported_by_runtime_system()` to compare the processor's featu
```c++ ```c++
for (auto implementation : simdjson::get_available_implementations()) { for (auto implementation : simdjson::get_available_implementations()) {
if(implementation->supported_by_runtime_system()) { if (implementation->supported_by_runtime_system()) {
cout << implementation->name() << ": " << implementation->description() << endl; cout << implementation->name() << ": " << implementation->description() << endl;
} }
} }
+51 -5
View File
@@ -17,6 +17,9 @@ Contents
- [Motivations](#motivations) - [Motivations](#motivations)
- [How it works](#how-it-works) - [How it works](#how-it-works)
- [Context](#context)
- [Design](#design)
- [Threads](#threads)
- [Support](#support) - [Support](#support)
- [API](#api) - [API](#api)
- [Use cases](#use-cases) - [Use cases](#use-cases)
@@ -129,6 +132,18 @@ Some official formats **(non-exhaustive list)**:
API API
--- ---
Example:
```c++
auto json = R"({ "foo": 1 } { "foo": 2 } { "foo": 3 } )"_padded;
ondemand::parser parser;
ondemand::document_stream docs = parser.iterate_many(json);
for (auto doc : docs) {
std::cout << doc["foo"] << std::endl;
}
// Prints 1 2 3
```
See [basics.md](basics.md#newline-delimited-json-ndjson-and-json-lines) for an overview of the API. See [basics.md](basics.md#newline-delimited-json-ndjson-and-json-lines) for an overview of the API.
## Use cases ## Use cases
@@ -181,12 +196,12 @@ Let us illustrate the idea with code:
simdjson::ondemand::parser parser; simdjson::ondemand::parser parser;
simdjson::ondemand::document_stream stream; simdjson::ondemand::document_stream stream;
auto error = parser.iterate_many(json).get(stream); auto error = parser.iterate_many(json).get(stream);
if( error ) { /* do something */ } if (error) { /* do something */ }
auto i = stream.begin(); auto i = stream.begin();
size_t count{0}; size_t count{0};
for(; i != stream.end(); ++i) { for(; i != stream.end(); ++i) {
auto doc = *i; auto doc = *i;
if(!i.error()) { if (!i.error()) {
std::cout << "got full document at " << i.current_index() << std::endl; std::cout << "got full document at " << i.current_index() << std::endl;
std::cout << i.source() << std::endl; std::cout << i.source() << std::endl;
count++; count++;
@@ -222,7 +237,7 @@ Consider the following example where a truncated document (`{"key":"intentionall
simdjson::ondemand::parser parser; simdjson::ondemand::parser parser;
simdjson::ondemand::document_stream stream; simdjson::ondemand::document_stream stream;
auto error = parser.iterate_many(json,json.size()).get(stream); auto error = parser.iterate_many(json,json.size()).get(stream);
if(error) { std::cerr << error << std::endl; return; } if (error) { std::cerr << error << std::endl; return; }
for(auto i = stream.begin(); i != stream.end(); ++i) { for(auto i = stream.begin(); i != stream.end(); ++i) {
std::cout << i.source() << std::endl; std::cout << i.source() << std::endl;
} }
@@ -238,7 +253,38 @@ This will print:
Importantly, you should only call `truncated_bytes()` after iterating through all of the documents since the stream cannot tell whether there are truncated documents at the very end when it may not have accessed that part of the data yet. Importantly, you should only call `truncated_bytes()` after iterating through all of the documents since the stream cannot tell whether there are truncated documents at the very end when it may not have accessed that part of the data yet.
Comma separated documents Comma-separated documents
----------- -----------
`iterate_many` also takes in an option to allow parsing of comma separated documents. In this mode, the entire buffer is processed in 1 batch and batch size will be increased to be as large as the JSON passed. Therefore, the capacity of the parser has to be sufficient to support the batch size set. We also support comma-separated documents, but with some performance limitations. The `iterate_many` function takes in an option to allow parsing of comma separated documents (which defaults on false). In this mode, the entire buffer is processed in one batch. Therefore, the total size of the document should not exceed the maximal capacity of the parser (4 GB). This mode also effectively disallow multithreading. It is therefore mostly suitable for not "very large" inputs. In this mode, the batch_size parameter
is effectively ignored, as it is set to at least the document size.
Example:
```C++
auto json = R"( 1, 2, 3, 4, "a", "b", "c", {"hello": "world"} , [1, 2, 3])"_padded;
ondemand::parser parser;
ondemand::document_stream doc_stream;
// We pass '32' as the batch size, but it is a bogus parameter because, since
// we pass 'true' to the allow_comma parameter, the batch size will be set to at least
// the document size.
auto error = parser.iterate_many(json, 32, true).get(doc_stream);
if (error) { std::cerr << error << std::endl; return; }
for (auto doc : doc_stream) {
std::cout << doc.type() << std::endl;
}
```
This will print:
```
number
number
number
number
string
string
string
object
array
```
+6 -6
View File
@@ -679,14 +679,14 @@ in production systems:
ondemand::object c1 = parent["child1"]; ondemand::object c1 = parent["child1"];
// c1 owns the focus // c1 owns the focus
// //
if(std::string_view(c1["name"]) != "John") { ... } if (std::string_view(c1["name"]) != "John") { ... }
// c2 attempts to grab the focus from parent but fails // c2 attempts to grab the focus from parent but fails
ondemand::object c2 = parent["child2"]; ondemand::object c2 = parent["child2"];
// c2 is now in an unsafe state and the following line would be unsafe // c2 is now in an unsafe state and the following line would be unsafe
// if(std::string_view(c2["name"]) != "Daniel") { return false; } // if (std::string_view(c2["name"]) != "Daniel") { return false; }
``` ```
A correct usage is given by the following example: A correct usage is given by the following example:
```C++ ```C++
ondemand::parser parser; ondemand::parser parser;
@@ -697,7 +697,7 @@ in production systems:
{ {
ondemand::object c1 = parent["child1"]; ondemand::object c1 = parent["child1"];
// c1 grabbed the focus from parent // c1 grabbed the focus from parent
if(std::string_view(c1["name"]) != "John") { return false; } if (std::string_view(c1["name"]) != "John") { return false; }
} }
// c1 went out of scope, so its destructor was called and the focus // c1 went out of scope, so its destructor was called and the focus
// was handed back to parent. // was handed back to parent.
@@ -705,7 +705,7 @@ in production systems:
ondemand::object c2 = parent["child2"]; ondemand::object c2 = parent["child2"];
// c2 grabbed the focus from parent // c2 grabbed the focus from parent
// the following is safe: // the following is safe:
if(std::string_view(c2["name"]) != "Daniel") { return false; } if (std::string_view(c2["name"]) != "Daniel") { return false; }
} }
``` ```
@@ -779,4 +779,4 @@ Instead of specifying a specific microarchitecture, you can let your compiler do
Passing `-march=native` to the compiler may make On Demand faster by allowing it to use optimizations specific to your machine. You cannot do this, however, if you are compiling code that might be run on less advanced machines. That is, be mindful that when compiling with the `-march=native` flag, the resulting binary will run on the current system but may not run on other systems (e.g., on an old processor). Passing `-march=native` to the compiler may make On Demand faster by allowing it to use optimizations specific to your machine. You cannot do this, however, if you are compiling code that might be run on less advanced machines. That is, be mindful that when compiling with the `-march=native` flag, the resulting binary will run on the current system but may not run on other systems (e.g., on an old processor).
If you are compiling on an ARM or POWER system, you do not need to be concerned with CPU selection during compilation. The `-march=native` flag useful for best performance on x64 (e.g., Intel) systems but it is generally unsupported on some platforms such as ARM (aarch64) or POWER. If you are compiling on an ARM or POWER system, you do not need to be concerned with CPU selection during compilation. The `-march=native` flag is useful for best performance on x64 (e.g., Intel) systems but it is generally unsupported on some platforms such as ARM (aarch64) or POWER.
+3 -3
View File
@@ -184,12 +184,12 @@ Let us illustrate the idea with code:
simdjson::dom::parser parser; simdjson::dom::parser parser;
simdjson::dom::document_stream stream; simdjson::dom::document_stream stream;
auto error = parser.parse_many(json).get(stream); auto error = parser.parse_many(json).get(stream);
if( error ) { /* do something */ } if (error) { /* do something */ }
auto i = stream.begin(); auto i = stream.begin();
size_t count{0}; size_t count{0};
for(; i != stream.end(); ++i) { for(; i != stream.end(); ++i) {
auto doc = *i; auto doc = *i;
if(!doc.error()) { if (!doc.error()) {
std::cout << "got full document at " << i.current_index() << std::endl; std::cout << "got full document at " << i.current_index() << std::endl;
std::cout << i.source() << std::endl; std::cout << i.source() << std::endl;
count++; count++;
@@ -225,7 +225,7 @@ Consider the following example where a truncated document (`{"key":"intentionall
simdjson::dom::parser parser; simdjson::dom::parser parser;
simdjson::dom::document_stream stream; simdjson::dom::document_stream stream;
auto error = parser.parse_many(json,json.size()).get(stream); auto error = parser.parse_many(json,json.size()).get(stream);
if(error) { std::cerr << error << std::endl; return; } if (error) { std::cerr << error << std::endl; return; }
for(auto doc : stream) { for(auto doc : stream) {
std::cout << doc << std::endl; std::cout << doc << std::endl;
} }
+1 -1
View File
@@ -159,7 +159,7 @@ When compiling with Visual Studio, we recommend the flags `/Ob2 /O2` or better.
Recent versions of Microsoft Visual Studio on Windows provides support for the LLVM Clang compiler. You only need to install the "Clang compiler" optional component (ClangCL). You may also get a copy of the 64-bit LLVM CLang compiler for [Windows directly from LLVM](https://releases.llvm.org/download.html). The simdjson library fully supports the LLVM Clang compiler under Windows. In fact, you may get better performance out of simdjson with the LLVM Clang compiler than with the regular Visual Studio compiler. Meanwhile the [LLVM CLang compiler is binary compatible with Visual Studio](https://clang.llvm.org/docs/MSVCCompatibility.html) which means that you can combine their binaries (executables and libraries). Recent versions of Microsoft Visual Studio on Windows provides support for the LLVM Clang compiler. You only need to install the "Clang compiler" optional component (ClangCL). You may also get a copy of the 64-bit LLVM CLang compiler for [Windows directly from LLVM](https://releases.llvm.org/download.html). The simdjson library fully supports the LLVM Clang compiler under Windows. In fact, you may get better performance out of simdjson with the LLVM Clang compiler than with the regular Visual Studio compiler. Meanwhile the [LLVM CLang compiler is binary compatible with Visual Studio](https://clang.llvm.org/docs/MSVCCompatibility.html) which means that you can combine their binaries (executables and libraries).
Under Windows, we also support the GNU GCC compiler via MSYS2. The performance of 64-bit MSYS2 under Windows excellent (on par with Linux). Under Windows, we also support the GNU GCC compiler via MSYS2. The performance of 64-bit MSYS2 under Windows is excellent (on par with Linux).
Power Usage and Downclocking Power Usage and Downclocking
+1 -1
View File
@@ -29,7 +29,7 @@ It is sometimes useful to start with an example. Consider the following JSON doc
The following is a dump of the content of the tape, with the first number of each line representing the index of a tape element. The following is a dump of the content of the tape, with the first number of each line representing the index of a tape element.
### The Tape ### The Tape
| index | element (64 bit word) | | index | element (64-bit word) |
| ----- | ------------------------------------------------------------------- | | ----- | ------------------------------------------------------------------- |
| 0 | r // pointing to 39 (right after last node) | | 0 | r // pointing to 39 (right after last node) |
| 1 | { // pointing to next tape location 38 (first node after the scope) | | 1 | { // pointing to next tape location 38 (first node after the scope) |
+1 -1
View File
@@ -78,7 +78,7 @@ fi
# Different levels may uncover different types of bugs, see this interesting # Different levels may uncover different types of bugs, see this interesting
# thread: https://github.com/google/oss-fuzz/issues/2295#issuecomment-481493392 # thread: https://github.com/google/oss-fuzz/issues/2295#issuecomment-481493392
# Oss-fuzz uses -O1 so it may be relevant to use something else than that, # Oss-fuzz uses -O1 so it may be relevant to use something else than that,
# to do something oss-fuzz doesn't. # to do something oss-fuzz does not do.
variant=sanitizers-O3 variant=sanitizers-O3
if [ ! -d build-$variant ] ; then if [ ! -d build-$variant ] ; then
+2 -2
View File
@@ -7,11 +7,11 @@
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
// Split data into two strings, json pointer and the document string. // Split data into two strings, JSON Pointer and the document string.
// Might end up with none, either or both being empty, important for // Might end up with none, either or both being empty, important for
// covering edge cases such as // covering edge cases such as
// https://github.com/simdjson/simdjson/issues/1142 Inputs missing the // https://github.com/simdjson/simdjson/issues/1142 Inputs missing the
// separator line will get an empty json pointer but the all the input put in // separator line will get an empty JSON Pointer but the all the input put in
// the document string. This means test data from other fuzzers that take json // the document string. This means test data from other fuzzers that take json
// input works for this fuzzer as well. // input works for this fuzzer as well.
FuzzData fd(Data, Size); FuzzData fd(Data, Size);
+17 -1
View File
@@ -34,8 +34,24 @@
} }
*/ */
#include "simdjson/common_defs.h"
// This provides the public API for simdjson.
// DOM and ondemand are amalgamated separately, in simdjson.h
#include "simdjson/simdjson_version.h" #include "simdjson/simdjson_version.h"
#include "simdjson/base.h"
#include "simdjson/error.h"
#include "simdjson/error-inl.h"
#include "simdjson/implementation.h"
#include "simdjson/minify.h"
#include "simdjson/padded_string.h"
#include "simdjson/padded_string-inl.h"
#include "simdjson/padded_string_view.h"
#include "simdjson/padded_string_view-inl.h"
#include "simdjson/dom.h" #include "simdjson/dom.h"
#include "simdjson/builtin.h" #include "simdjson/ondemand.h"
#endif // SIMDJSON_H #endif // SIMDJSON_H
+2 -28
View File
@@ -1,34 +1,8 @@
#ifndef SIMDJSON_ARM64_H #ifndef SIMDJSON_ARM64_H
#define SIMDJSON_ARM64_H #define SIMDJSON_ARM64_H
#include "simdjson/implementation-base.h"
#if SIMDJSON_IMPLEMENTATION_ARM64
namespace simdjson {
/**
* Implementation for NEON (ARMv8).
*/
namespace arm64 {
} // namespace arm64
} // namespace simdjson
#include "simdjson/arm64/implementation.h"
#include "simdjson/arm64/begin.h" #include "simdjson/arm64/begin.h"
#include "simdjson/generic/amalgamated.h"
// Declarations
#include "simdjson/generic/dom_parser_implementation.h"
#include "simdjson/arm64/intrinsics.h"
#include "simdjson/arm64/bitmanipulation.h"
#include "simdjson/arm64/bitmask.h"
#include "simdjson/arm64/simd.h"
#include "simdjson/generic/jsoncharutils.h"
#include "simdjson/generic/atomparsing.h"
#include "simdjson/arm64/stringparsing.h"
#include "simdjson/arm64/numberparsing.h"
#include "simdjson/arm64/end.h" #include "simdjson/arm64/end.h"
#endif // SIMDJSON_IMPLEMENTATION_ARM64 #endif // SIMDJSON_ARM64_H
#endif // SIMDJSON_ARM64_H
+26
View File
@@ -0,0 +1,26 @@
#ifndef SIMDJSON_ARM64_BASE_H
#define SIMDJSON_ARM64_BASE_H
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#include "simdjson/base.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
namespace simdjson {
/**
* Implementation for NEON (ARMv8).
*/
namespace arm64 {
class implementation;
namespace {
namespace simd {
template <typename T> struct simd8;
template <typename T> struct simd8x64;
} // namespace simd
} // unnamed namespace
} // namespace arm64
} // namespace simdjson
#endif // SIMDJSON_ARM64_BASE_H
+9
View File
@@ -1 +1,10 @@
#define SIMDJSON_IMPLEMENTATION arm64 #define SIMDJSON_IMPLEMENTATION arm64
#include "simdjson/arm64/base.h"
#include "simdjson/arm64/intrinsics.h"
#include "simdjson/arm64/bitmanipulation.h"
#include "simdjson/arm64/bitmask.h"
#include "simdjson/arm64/numberparsing_defs.h"
#include "simdjson/arm64/simd.h"
#include "simdjson/arm64/stringparsing_defs.h"
#define SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT 1
+7 -2
View File
@@ -1,8 +1,13 @@
#ifndef SIMDJSON_ARM64_BITMANIPULATION_H #ifndef SIMDJSON_ARM64_BITMANIPULATION_H
#define SIMDJSON_ARM64_BITMANIPULATION_H #define SIMDJSON_ARM64_BITMANIPULATION_H
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#include "simdjson/arm64/base.h"
#include "simdjson/arm64/intrinsics.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
namespace simdjson { namespace simdjson {
namespace SIMDJSON_IMPLEMENTATION { namespace arm64 {
namespace { namespace {
// We sometimes call trailing_zero on inputs that are zero, // We sometimes call trailing_zero on inputs that are zero,
@@ -95,7 +100,7 @@ simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *re
} }
} // unnamed namespace } // unnamed namespace
} // namespace SIMDJSON_IMPLEMENTATION } // namespace arm64
} // namespace simdjson } // namespace simdjson
#endif // SIMDJSON_ARM64_BITMANIPULATION_H #endif // SIMDJSON_ARM64_BITMANIPULATION_H
+5 -1
View File
@@ -1,8 +1,12 @@
#ifndef SIMDJSON_ARM64_BITMASK_H #ifndef SIMDJSON_ARM64_BITMASK_H
#define SIMDJSON_ARM64_BITMASK_H #define SIMDJSON_ARM64_BITMASK_H
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#include "simdjson/arm64/base.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
namespace simdjson { namespace simdjson {
namespace SIMDJSON_IMPLEMENTATION { namespace arm64 {
namespace { namespace {
// //
+5
View File
@@ -1 +1,6 @@
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#include "simdjson/arm64/base.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
#undef SIMDJSON_SKIP_BACKSLASH_SHORT_CIRCUIT
#undef SIMDJSON_IMPLEMENTATION #undef SIMDJSON_IMPLEMENTATION
+4 -6
View File
@@ -1,17 +1,15 @@
#ifndef SIMDJSON_ARM64_IMPLEMENTATION_H #ifndef SIMDJSON_ARM64_IMPLEMENTATION_H
#define SIMDJSON_ARM64_IMPLEMENTATION_H #define SIMDJSON_ARM64_IMPLEMENTATION_H
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#include "simdjson/base.h" #include "simdjson/base.h"
#include "simdjson/internal/isadetection.h" #include "simdjson/implementation.h"
#include "simdjson/internal/instruction_set.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
namespace simdjson { namespace simdjson {
namespace arm64 { namespace arm64 {
namespace {
using namespace simdjson;
using namespace simdjson::dom;
}
/** /**
* @private * @private
*/ */
+4
View File
@@ -1,6 +1,10 @@
#ifndef SIMDJSON_ARM64_INTRINSICS_H #ifndef SIMDJSON_ARM64_INTRINSICS_H
#define SIMDJSON_ARM64_INTRINSICS_H #define SIMDJSON_ARM64_INTRINSICS_H
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#include "simdjson/arm64/base.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
// This should be the correct header whether // This should be the correct header whether
// you use visual studio or other compilers. // you use visual studio or other compilers.
#include <arm_neon.h> #include <arm_neon.h>
-26
View File
@@ -1,26 +0,0 @@
#ifndef SIMDJSON_ARM64_NUMBERPARSING_H
#define SIMDJSON_ARM64_NUMBERPARSING_H
namespace simdjson {
namespace SIMDJSON_IMPLEMENTATION {
namespace {
// we don't have SSE, so let us use a scalar function
// credit: https://johnnylee-sde.github.io/Fast-numeric-string-to-int/
static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) {
uint64_t val;
std::memcpy(&val, chars, sizeof(uint64_t));
val = (val & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8;
val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16;
return uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32);
}
} // unnamed namespace
} // namespace SIMDJSON_IMPLEMENTATION
} // namespace simdjson
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#include "simdjson/generic/numberparsing.h"
#endif // SIMDJSON_ARM64_NUMBERPARSING_H
@@ -0,0 +1,56 @@
#ifndef SIMDJSON_ARM64_NUMBERPARSING_DEFS_H
#define SIMDJSON_ARM64_NUMBERPARSING_DEFS_H
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#include "simdjson/arm64/base.h"
#include "simdjson/arm64/intrinsics.h"
#include "simdjson/internal/numberparsing_tables.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
#include <cstring>
#if _M_ARM64
// __umulh requires intrin.h
#include <intrin.h>
#endif // _M_ARM64
namespace simdjson {
namespace arm64 {
namespace numberparsing {
// we don't have SSE, so let us use a scalar function
// credit: https://johnnylee-sde.github.io/Fast-numeric-string-to-int/
/** @private */
static simdjson_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) {
uint64_t val;
std::memcpy(&val, chars, sizeof(uint64_t));
val = (val & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8;
val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16;
return uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32);
}
simdjson_inline internal::value128 full_multiplication(uint64_t value1, uint64_t value2) {
internal::value128 answer;
#if SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
#ifdef _M_ARM64
// ARM64 has native support for 64-bit multiplications, no need to emultate
answer.high = __umulh(value1, value2);
answer.low = value1 * value2;
#else
answer.low = _umul128(value1, value2, &answer.high); // _umul128 not available on ARM64
#endif // _M_ARM64
#else // SIMDJSON_REGULAR_VISUAL_STUDIO || SIMDJSON_IS_32BITS
__uint128_t r = (static_cast<__uint128_t>(value1)) * value2;
answer.low = uint64_t(r);
answer.high = uint64_t(r >> 64);
#endif
return answer;
}
} // namespace numberparsing
} // namespace arm64
} // namespace simdjson
#define SIMDJSON_SWAR_NUMBER_PARSING 1
#endif // SIMDJSON_ARM64_NUMBERPARSING_DEFS_H
+8
View File
@@ -0,0 +1,8 @@
#ifndef SIMDJSON_ARM64_ONDEMAND_H
#define SIMDJSON_ARM64_ONDEMAND_H
#include "simdjson/arm64/begin.h"
#include "simdjson/generic/ondemand/amalgamated.h"
#include "simdjson/arm64/end.h"
#endif // SIMDJSON_ARM64_ONDEMAND_H
+58 -94
View File
@@ -1,14 +1,14 @@
#ifndef SIMDJSON_ARM64_SIMD_H #ifndef SIMDJSON_ARM64_SIMD_H
#define SIMDJSON_ARM64_SIMD_H #define SIMDJSON_ARM64_SIMD_H
#include "simdjson/base.h" #ifndef SIMDJSON_CONDITIONAL_INCLUDE
#include "simdjson/internal/simdprune_tables.h" #include "simdjson/arm64/base.h"
#include "simdjson/arm64/bitmanipulation.h" #include "simdjson/arm64/bitmanipulation.h"
#include <type_traits> #include "simdjson/internal/simdprune_tables.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
namespace simdjson { namespace simdjson {
namespace SIMDJSON_IMPLEMENTATION { namespace arm64 {
namespace { namespace {
namespace simd { namespace simd {
@@ -17,89 +17,53 @@ namespace {
// Start of private section with Visual Studio workaround // Start of private section with Visual Studio workaround
/** #ifndef simdjson_make_uint8x16_t
* make_uint8x16_t initializes a SIMD register (uint8x16_t). #define simdjson_make_uint8x16_t(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, \
* This is needed because, incredibly, the syntax uint8x16_t x = {1,2,3...} x13, x14, x15, x16) \
* is not recognized under Visual Studio! This is a workaround. ([=]() { \
* Using a std::initializer_list<uint8_t> as a parameter resulted in uint8_t array[16] = {x1, x2, x3, x4, x5, x6, x7, x8, \
* inefficient code. With the current approach, if the parameters are x9, x10, x11, x12, x13, x14, x15, x16}; \
* compile-time constants, return vld1q_u8(array); \
* GNU GCC compiles it to ldr, the same as uint8x16_t x = {1,2,3...}. }())
* You should not use this function except for compile-time constants: #endif
* it is not efficient. #ifndef simdjson_make_int8x16_t
*/ #define simdjson_make_int8x16_t(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, \
simdjson_inline uint8x16_t make_uint8x16_t(uint8_t x1, uint8_t x2, uint8_t x3, uint8_t x4, x13, x14, x15, x16) \
uint8_t x5, uint8_t x6, uint8_t x7, uint8_t x8, ([=]() { \
uint8_t x9, uint8_t x10, uint8_t x11, uint8_t x12, int8_t array[16] = {x1, x2, x3, x4, x5, x6, x7, x8, \
uint8_t x13, uint8_t x14, uint8_t x15, uint8_t x16) { x9, x10, x11, x12, x13, x14, x15, x16}; \
// Doing a load like so end ups generating worse code. return vld1q_s8(array); \
// uint8_t array[16] = {x1, x2, x3, x4, x5, x6, x7, x8, }())
// x9, x10,x11,x12,x13,x14,x15,x16}; #endif
// return vld1q_u8(array);
uint8x16_t x{};
// incredibly, Visual Studio does not allow x[0] = x1
x = vsetq_lane_u8(x1, x, 0);
x = vsetq_lane_u8(x2, x, 1);
x = vsetq_lane_u8(x3, x, 2);
x = vsetq_lane_u8(x4, x, 3);
x = vsetq_lane_u8(x5, x, 4);
x = vsetq_lane_u8(x6, x, 5);
x = vsetq_lane_u8(x7, x, 6);
x = vsetq_lane_u8(x8, x, 7);
x = vsetq_lane_u8(x9, x, 8);
x = vsetq_lane_u8(x10, x, 9);
x = vsetq_lane_u8(x11, x, 10);
x = vsetq_lane_u8(x12, x, 11);
x = vsetq_lane_u8(x13, x, 12);
x = vsetq_lane_u8(x14, x, 13);
x = vsetq_lane_u8(x15, x, 14);
x = vsetq_lane_u8(x16, x, 15);
return x;
}
simdjson_inline uint8x8_t make_uint8x8_t(uint8_t x1, uint8_t x2, uint8_t x3, uint8_t x4, #ifndef simdjson_make_uint8x8_t
uint8_t x5, uint8_t x6, uint8_t x7, uint8_t x8) { #define simdjson_make_uint8x8_t(x1, x2, x3, x4, x5, x6, x7, x8) \
uint8x8_t x{}; ([=]() { \
x = vset_lane_u8(x1, x, 0); uint8_t array[8] = {x1, x2, x3, x4, x5, x6, x7, x8}; \
x = vset_lane_u8(x2, x, 1); return vld1_u8(array); \
x = vset_lane_u8(x3, x, 2); }())
x = vset_lane_u8(x4, x, 3); #endif
x = vset_lane_u8(x5, x, 4); #ifndef simdjson_make_int8x8_t
x = vset_lane_u8(x6, x, 5); #define simdjson_make_int8x8_t(x1, x2, x3, x4, x5, x6, x7, x8) \
x = vset_lane_u8(x7, x, 6); ([=]() { \
x = vset_lane_u8(x8, x, 7); int8_t array[8] = {x1, x2, x3, x4, x5, x6, x7, x8}; \
return x; return vld1_s8(array); \
} }())
#endif
// We have to do the same work for make_int8x16_t #ifndef simdjson_make_uint16x8_t
simdjson_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int8_t x4, #define simdjson_make_uint16x8_t(x1, x2, x3, x4, x5, x6, x7, x8) \
int8_t x5, int8_t x6, int8_t x7, int8_t x8, ([=]() { \
int8_t x9, int8_t x10, int8_t x11, int8_t x12, uint16_t array[8] = {x1, x2, x3, x4, x5, x6, x7, x8}; \
int8_t x13, int8_t x14, int8_t x15, int8_t x16) { return vld1q_u16(array); \
// Doing a load like so end ups generating worse code. }())
// int8_t array[16] = {x1, x2, x3, x4, x5, x6, x7, x8, #endif
// x9, x10,x11,x12,x13,x14,x15,x16}; #ifndef simdjson_make_int16x8_t
// return vld1q_s8(array); #define simdjson_make_int16x8_t(x1, x2, x3, x4, x5, x6, x7, x8) \
int8x16_t x{}; ([=]() { \
// incredibly, Visual Studio does not allow x[0] = x1 int16_t array[8] = {x1, x2, x3, x4, x5, x6, x7, x8}; \
x = vsetq_lane_s8(x1, x, 0); return vld1q_s16(array); \
x = vsetq_lane_s8(x2, x, 1); }())
x = vsetq_lane_s8(x3, x, 2); #endif
x = vsetq_lane_s8(x4, x, 3);
x = vsetq_lane_s8(x5, x, 4);
x = vsetq_lane_s8(x6, x, 5);
x = vsetq_lane_s8(x7, x, 6);
x = vsetq_lane_s8(x8, x, 7);
x = vsetq_lane_s8(x9, x, 8);
x = vsetq_lane_s8(x10, x, 9);
x = vsetq_lane_s8(x11, x, 10);
x = vsetq_lane_s8(x12, x, 11);
x = vsetq_lane_s8(x13, x, 12);
x = vsetq_lane_s8(x14, x, 13);
x = vsetq_lane_s8(x15, x, 14);
x = vsetq_lane_s8(x16, x, 15);
return x;
}
// End of private section with Visual Studio workaround // End of private section with Visual Studio workaround
} // namespace } // namespace
@@ -158,7 +122,7 @@ simdjson_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int
// purposes (cutting it down to uint16_t costs performance in some compilers). // purposes (cutting it down to uint16_t costs performance in some compilers).
simdjson_inline uint32_t to_bitmask() const { simdjson_inline uint32_t to_bitmask() const {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO #ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
const uint8x16_t bit_mask = make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, const uint8x16_t bit_mask = simdjson_make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80); 0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80);
#else #else
const uint8x16_t bit_mask = {0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, const uint8x16_t bit_mask = {0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
@@ -192,7 +156,7 @@ simdjson_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int
simdjson_inline simd8( simdjson_inline simd8(
uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7, uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7,
uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15 uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
) : simd8(make_uint8x16_t( ) : simd8(simdjson_make_uint8x16_t(
v0, v1, v2, v3, v4, v5, v6, v7, v0, v1, v2, v3, v4, v5, v6, v7,
v8, v9, v10,v11,v12,v13,v14,v15 v8, v9, v10,v11,v12,v13,v14,v15
)) {} )) {}
@@ -283,7 +247,7 @@ simdjson_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int
uint8x16_t shufmask = vreinterpretq_u8_u64(shufmask64); uint8x16_t shufmask = vreinterpretq_u8_u64(shufmask64);
// we increment by 0x08 the second half of the mask // we increment by 0x08 the second half of the mask
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO #ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
uint8x16_t inc = make_uint8x16_t(0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08); uint8x16_t inc = simdjson_make_uint8x16_t(0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
#else #else
uint8x16_t inc = {0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}; uint8x16_t inc = {0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
#endif #endif
@@ -313,7 +277,7 @@ simdjson_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int
uint8x8_t compactmask2 = vcreate_u8(thintable_epi8[mask2]); uint8x8_t compactmask2 = vcreate_u8(thintable_epi8[mask2]);
// we increment by 0x08 the second half of the mask // we increment by 0x08 the second half of the mask
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO #ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
uint8x8_t inc = make_uint8x8_t(0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08); uint8x8_t inc = simdjson_make_uint8x8_t(0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08);
#else #else
uint8x8_t inc = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}; uint8x8_t inc = {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
#endif #endif
@@ -368,7 +332,7 @@ simdjson_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int
simdjson_inline simd8( simdjson_inline simd8(
int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5, int8_t v6, int8_t v7, int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5, int8_t v6, int8_t v7,
int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15 int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
) : simd8(make_int8x16_t( ) : simd8(simdjson_make_int8x16_t(
v0, v1, v2, v3, v4, v5, v6, v7, v0, v1, v2, v3, v4, v5, v6, v7,
v8, v9, v10,v11,v12,v13,v14,v15 v8, v9, v10,v11,v12,v13,v14,v15
)) {} )) {}
@@ -486,7 +450,7 @@ simdjson_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int
simdjson_inline uint64_t to_bitmask() const { simdjson_inline uint64_t to_bitmask() const {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO #ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
const uint8x16_t bit_mask = make_uint8x16_t( const uint8x16_t bit_mask = simdjson_make_uint8x16_t(
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80 0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80
); );
@@ -527,7 +491,7 @@ simdjson_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int
} // namespace simd } // namespace simd
} // unnamed namespace } // unnamed namespace
} // namespace SIMDJSON_IMPLEMENTATION } // namespace arm64
} // namespace simdjson } // namespace simdjson
#endif // SIMDJSON_ARM64_SIMD_H #endif // SIMDJSON_ARM64_SIMD_H
@@ -1,12 +1,14 @@
#ifndef SIMDJSON_ARM64_STRINGPARSING_H #ifndef SIMDJSON_ARM64_STRINGPARSING_DEFS_H
#define SIMDJSON_ARM64_STRINGPARSING_H #define SIMDJSON_ARM64_STRINGPARSING_DEFS_H
#include "simdjson/base.h" #ifndef SIMDJSON_CONDITIONAL_INCLUDE
#include "simdjson/arm64/base.h"
#include "simdjson/arm64/simd.h" #include "simdjson/arm64/simd.h"
#include "simdjson/arm64/bitmanipulation.h" #include "simdjson/arm64/bitmanipulation.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
namespace simdjson { namespace simdjson {
namespace SIMDJSON_IMPLEMENTATION { namespace arm64 {
namespace { namespace {
using namespace simd; using namespace simd;
@@ -45,7 +47,7 @@ simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uin
} }
} // unnamed namespace } // unnamed namespace
} // namespace SIMDJSON_IMPLEMENTATION } // namespace arm64
} // namespace simdjson } // namespace simdjson
#endif // SIMDJSON_ARM64_STRINGPARSING_H #endif // SIMDJSON_ARM64_STRINGPARSING_DEFS_H
+50 -16
View File
@@ -1,26 +1,60 @@
/**
* @file Base declarations for all simdjson headers
* @private
*/
#ifndef SIMDJSON_BASE_H #ifndef SIMDJSON_BASE_H
#define SIMDJSON_BASE_H #define SIMDJSON_BASE_H
#include "simdjson/compiler_check.h"
#include "simdjson/common_defs.h" #include "simdjson/common_defs.h"
#include "simdjson/compiler_check.h"
#include "simdjson/error.h"
#include "simdjson/portability.h" #include "simdjson/portability.h"
SIMDJSON_PUSH_DISABLE_WARNINGS /**
SIMDJSON_DISABLE_UNDESIRED_WARNINGS * @brief The top level simdjson namespace, containing everything the library provides.
*/
namespace simdjson {
// Public API SIMDJSON_PUSH_DISABLE_UNUSED_WARNINGS
#include "simdjson/simdjson_version.h"
#include "simdjson/error.h"
#include "simdjson/minify.h"
#include "simdjson/padded_string.h"
#include "simdjson/padded_string_view.h"
#include "simdjson/implementation.h"
// Inline functions /** The maximum document size supported by simdjson. */
#include "simdjson/error-inl.h" constexpr size_t SIMDJSON_MAXSIZE_BYTES = 0xFFFFFFFF;
#include "simdjson/padded_string-inl.h"
#include "simdjson/padded_string_view-inl.h"
SIMDJSON_POP_DISABLE_WARNINGS /**
* The amount of padding needed in a buffer to parse JSON.
*
* The input buf should be readable up to buf + SIMDJSON_PADDING
* this is a stopgap; there should be a better description of the
* main loop and its behavior that abstracts over this
* See https://github.com/simdjson/simdjson/issues/174
*/
constexpr size_t SIMDJSON_PADDING = 64;
#endif // SIMDJSON_BASE_H /**
* By default, simdjson supports this many nested objects and arrays.
*
* This is the default for parser::max_depth().
*/
constexpr size_t DEFAULT_MAX_DEPTH = 1024;
SIMDJSON_POP_DISABLE_UNUSED_WARNINGS
class implementation;
struct padded_string;
class padded_string_view;
enum class stage1_mode;
namespace internal {
template<typename T>
class atomic_ptr;
class dom_parser_implementation;
class escape_json_string;
class tape_ref;
struct value128;
enum class tape_type;
} // namespace internal
} // namespace simdjson
#endif // SIMDJSON_BASE_H
+20 -55
View File
@@ -1,64 +1,29 @@
#ifndef SIMDJSON_BUILTIN_H #ifndef SIMDJSON_BUILTIN_H
#define SIMDJSON_BUILTIN_H #define SIMDJSON_BUILTIN_H
#include "simdjson/implementations.h" #include "simdjson/builtin/base.h"
#include "simdjson/builtin/implementation.h"
// Determine the best builtin implementation #include "simdjson/generic/dependencies.h"
#ifndef SIMDJSON_BUILTIN_IMPLEMENTATION
#if SIMDJSON_CAN_ALWAYS_RUN_ICELAKE #define SIMDJSON_CONDITIONAL_INCLUDE
#define SIMDJSON_BUILTIN_IMPLEMENTATION icelake
#elif SIMDJSON_CAN_ALWAYS_RUN_HASWELL #if SIMDJSON_BUILTIN_IMPLEMENTATION_IS(arm64)
#define SIMDJSON_BUILTIN_IMPLEMENTATION haswell #include "simdjson/arm64.h"
#elif SIMDJSON_CAN_ALWAYS_RUN_WESTMERE #elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(fallback)
#define SIMDJSON_BUILTIN_IMPLEMENTATION westmere #include "simdjson/fallback.h"
#elif SIMDJSON_CAN_ALWAYS_RUN_ARM64 #elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(haswell)
#define SIMDJSON_BUILTIN_IMPLEMENTATION arm64 #include "simdjson/haswell.h"
#elif SIMDJSON_CAN_ALWAYS_RUN_PPC64 #elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(icelake)
#define SIMDJSON_BUILTIN_IMPLEMENTATION ppc64 #include "simdjson/icelake.h"
#elif SIMDJSON_CAN_ALWAYS_RUN_FALLBACK #elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(ppc64)
#define SIMDJSON_BUILTIN_IMPLEMENTATION fallback #include "simdjson/ppc64.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(westmere)
#include "simdjson/westmere.h"
#else #else
#error "All possible implementations (including fallback) have been disabled! simdjson will not run." #error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
#endif #endif
#endif // SIMDJSON_BUILTIN_IMPLEMENTATION
#define SIMDJSON_IMPLEMENTATION SIMDJSON_BUILTIN_IMPLEMENTATION #undef SIMDJSON_CONDITIONAL_INCLUDE
// ondemand is only compiled as part of the builtin implementation at present
// Interface declarations
#include "simdjson/generic/implementation_simdjson_result_base.h"
#include "simdjson/generic/ondemand.h"
// Inline definitions
#include "simdjson/generic/implementation_simdjson_result_base-inl.h"
#include "simdjson/generic/ondemand-inl.h"
#undef SIMDJSON_IMPLEMENTATION
namespace simdjson {
/**
* Represents the best statically linked simdjson implementation that can be used by the compiling
* program.
*
* Detects what options the program is compiled against, and picks the minimum implementation that
* will work on any computer that can run the program. For example, if you compile with g++
* -march=westmere, it will pick the westmere implementation. The haswell implementation will
* still be available, and can be selected at runtime, but the builtin implementation (and any
* code that uses it) will use westmere.
*/
namespace builtin = SIMDJSON_BUILTIN_IMPLEMENTATION;
/**
* @copydoc simdjson::SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand
*/
namespace ondemand = SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand;
/**
* Function which returns a pointer to an implementation matching the "builtin" implementation.
* The builtin implementation is the best statically linked simdjson implementation that can be used by the compiling
* program. If you compile with g++ -march=haswell, this will return the haswell implementation.
* It is handy to be able to check what builtin was used: builtin_implementation()->name().
*/
const implementation * builtin_implementation();
} // namespace simdjson
#endif // SIMDJSON_BUILTIN_H #endif // SIMDJSON_BUILTIN_H
+37
View File
@@ -0,0 +1,37 @@
#ifndef SIMDJSON_BUILTIN_BASE_H
#define SIMDJSON_BUILTIN_BASE_H
#include "simdjson/base.h"
#include "simdjson/implementation_detection.h"
namespace simdjson {
#if SIMDJSON_BUILTIN_IMPLEMENTATION_IS(arm64)
namespace arm64 {}
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(fallback)
namespace fallback {}
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(haswell)
namespace haswell {}
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(icelake)
namespace icelake {}
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(ppc64)
namespace ppc64 {}
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(westmere)
namespace westmere {}
#else
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
#endif
/**
* Represents the best statically linked simdjson implementation that can be used by the compiling
* program.
*
* Detects what options the program is compiled against, and picks the minimum implementation that
* will work on any computer that can run the program. For example, if you compile with g++
* -march=westmere, it will pick the westmere implementation. The haswell implementation will
* still be available, and can be selected at runtime, but the builtin implementation (and any
* code that uses it) will use westmere.
*/
namespace builtin = SIMDJSON_BUILTIN_IMPLEMENTATION;
} // namespace simdjson
#endif // SIMDJSON_BUILTIN_BASE_H
+38
View File
@@ -0,0 +1,38 @@
#ifndef SIMDJSON_BUILTIN_IMPLEMENTATION_H
#define SIMDJSON_BUILTIN_IMPLEMENTATION_H
#include "simdjson/builtin/base.h"
#include "simdjson/generic/dependencies.h"
#define SIMDJSON_CONDITIONAL_INCLUDE
#if SIMDJSON_BUILTIN_IMPLEMENTATION_IS(arm64)
#include "simdjson/arm64/implementation.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(fallback)
#include "simdjson/fallback/implementation.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(haswell)
#include "simdjson/haswell/implementation.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(icelake)
#include "simdjson/icelake/implementation.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(ppc64)
#include "simdjson/ppc64/implementation.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(westmere)
#include "simdjson/westmere/implementation.h"
#else
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
#endif
#undef SIMDJSON_CONDITIONAL_INCLUDE
namespace simdjson {
/**
* Function which returns a pointer to an implementation matching the "builtin" implementation.
* The builtin implementation is the best statically linked simdjson implementation that can be used by the compiling
* program. If you compile with g++ -march=haswell, this will return the haswell implementation.
* It is handy to be able to check what builtin was used: builtin_implementation()->name().
*/
const implementation * builtin_implementation();
} // namespace simdjson
#endif // SIMDJSON_BUILTIN_IMPLEMENTATION_H
+36
View File
@@ -0,0 +1,36 @@
#ifndef SIMDJSON_BUILTIN_ONDEMAND_H
#define SIMDJSON_BUILTIN_ONDEMAND_H
#include "simdjson/builtin.h"
#include "simdjson/builtin/base.h"
#include "simdjson/generic/ondemand/dependencies.h"
#define SIMDJSON_CONDITIONAL_INCLUDE
#if SIMDJSON_BUILTIN_IMPLEMENTATION_IS(arm64)
#include "simdjson/arm64/ondemand.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(fallback)
#include "simdjson/fallback/ondemand.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(haswell)
#include "simdjson/haswell/ondemand.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(icelake)
#include "simdjson/icelake/ondemand.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(ppc64)
#include "simdjson/ppc64/ondemand.h"
#elif SIMDJSON_BUILTIN_IMPLEMENTATION_IS(westmere)
#include "simdjson/westmere/ondemand.h"
#else
#error Unknown SIMDJSON_BUILTIN_IMPLEMENTATION
#endif
#undef SIMDJSON_CONDITIONAL_INCLUDE
namespace simdjson {
/**
* @copydoc simdjson::SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand
*/
namespace ondemand = SIMDJSON_BUILTIN_IMPLEMENTATION::ondemand;
} // namespace simdjson
#endif // SIMDJSON_BUILTIN_ONDEMAND_H
+31 -24
View File
@@ -2,10 +2,10 @@
#define SIMDJSON_COMMON_DEFS_H #define SIMDJSON_COMMON_DEFS_H
#include <cassert> #include <cassert>
#include "simdjson/compiler_check.h"
#include "simdjson/portability.h" #include "simdjson/portability.h"
namespace simdjson { namespace simdjson {
namespace internal { namespace internal {
/** /**
* @private * @private
@@ -20,7 +20,6 @@ char *to_chars(char *first, const char *last, double value);
*/ */
double from_chars(const char *first) noexcept; double from_chars(const char *first) noexcept;
double from_chars(const char *first, const char* end) noexcept; double from_chars(const char *first, const char* end) noexcept;
} }
#ifndef SIMDJSON_EXCEPTIONS #ifndef SIMDJSON_EXCEPTIONS
@@ -31,26 +30,6 @@ double from_chars(const char *first, const char* end) noexcept;
#endif #endif
#endif #endif
/** The maximum document size supported by simdjson. */
constexpr size_t SIMDJSON_MAXSIZE_BYTES = 0xFFFFFFFF;
/**
* The amount of padding needed in a buffer to parse JSON.
*
* The input buf should be readable up to buf + SIMDJSON_PADDING
* this is a stopgap; there should be a better description of the
* main loop and its behavior that abstracts over this
* See https://github.com/simdjson/simdjson/issues/174
*/
constexpr size_t SIMDJSON_PADDING = 64;
/**
* By default, simdjson supports this many nested objects and arrays.
*
* This is the default for parser::max_depth().
*/
constexpr size_t DEFAULT_MAX_DEPTH = 1024;
} // namespace simdjson } // namespace simdjson
#if defined(__GNUC__) #if defined(__GNUC__)
@@ -105,6 +84,9 @@ constexpr size_t DEFAULT_MAX_DEPTH = 1024;
#define SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING #define SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING
#define SIMDJSON_POP_DISABLE_WARNINGS __pragma(warning( pop )) #define SIMDJSON_POP_DISABLE_WARNINGS __pragma(warning( pop ))
#define SIMDJSON_PUSH_DISABLE_UNUSED_WARNINGS
#define SIMDJSON_POP_DISABLE_UNUSED_WARNINGS
#else // SIMDJSON_REGULAR_VISUAL_STUDIO #else // SIMDJSON_REGULAR_VISUAL_STUDIO
#define simdjson_really_inline inline __attribute__((always_inline)) #define simdjson_really_inline inline __attribute__((always_inline))
@@ -150,7 +132,8 @@ constexpr size_t DEFAULT_MAX_DEPTH = 1024;
SIMDJSON_DISABLE_GCC_WARNING(-Wshadow) \ SIMDJSON_DISABLE_GCC_WARNING(-Wshadow) \
SIMDJSON_DISABLE_GCC_WARNING(-Wunused-parameter) \ SIMDJSON_DISABLE_GCC_WARNING(-Wunused-parameter) \
SIMDJSON_DISABLE_GCC_WARNING(-Wunused-variable) \ SIMDJSON_DISABLE_GCC_WARNING(-Wunused-variable) \
SIMDJSON_DISABLE_GCC_WARNING(-Wmaybe-uninitialized) SIMDJSON_DISABLE_GCC_WARNING(-Wmaybe-uninitialized) \
SIMDJSON_DISABLE_GCC_WARNING(-Wformat-security)
#endif // __clang__ #endif // __clang__
#define SIMDJSON_PRAGMA(P) _Pragma(#P) #define SIMDJSON_PRAGMA(P) _Pragma(#P)
@@ -164,6 +147,10 @@ constexpr size_t DEFAULT_MAX_DEPTH = 1024;
#define SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING SIMDJSON_DISABLE_GCC_WARNING(-Wstrict-overflow) #define SIMDJSON_DISABLE_STRICT_OVERFLOW_WARNING SIMDJSON_DISABLE_GCC_WARNING(-Wstrict-overflow)
#define SIMDJSON_POP_DISABLE_WARNINGS _Pragma("GCC diagnostic pop") #define SIMDJSON_POP_DISABLE_WARNINGS _Pragma("GCC diagnostic pop")
#define SIMDJSON_PUSH_DISABLE_UNUSED_WARNINGS SIMDJSON_PUSH_DISABLE_WARNINGS \
SIMDJSON_DISABLE_GCC_WARNING(-Wunused)
#define SIMDJSON_POP_DISABLE_UNUSED_WARNINGS SIMDJSON_POP_DISABLE_WARNINGS
#endif // MSC_VER #endif // MSC_VER
@@ -322,7 +309,6 @@ namespace std {
# define simdjson_fallthrough do {} while (0) /* fallthrough */ # define simdjson_fallthrough do {} while (0) /* fallthrough */
#endif // simdjson_fallthrough #endif // simdjson_fallthrough
#if SIMDJSON_DEVELOPMENT_CHECKS #if SIMDJSON_DEVELOPMENT_CHECKS
#define SIMDJSON_DEVELOPMENT_ASSERT(expr) do { assert ((expr)); } while (0) #define SIMDJSON_DEVELOPMENT_ASSERT(expr) do { assert ((expr)); } while (0)
#else #else
@@ -333,4 +319,25 @@ namespace std {
#define SIMDJSON_UTF8VALIDATION 1 #define SIMDJSON_UTF8VALIDATION 1
#endif #endif
#ifdef __has_include
// How do we detect that a compiler supports vbmi2?
// For sure if the following header is found, we are ok?
#if __has_include(<avx512vbmi2intrin.h>)
#define SIMDJSON_COMPILER_SUPPORTS_VBMI2 1
#endif
#endif
#ifdef _MSC_VER
#if _MSC_VER >= 1920
// Visual Studio 2019 and up support VBMI2 under x64 even if the header
// avx512vbmi2intrin.h is not found.
#define SIMDJSON_COMPILER_SUPPORTS_VBMI2 1
#endif
#endif
// By default, we allow AVX512.
#ifndef SIMDJSON_AVX512_ALLOWED
#define SIMDJSON_AVX512_ALLOWED 1
#endif
#endif // SIMDJSON_COMMON_DEFS_H #endif // SIMDJSON_COMMON_DEFS_H
+8
View File
@@ -32,4 +32,12 @@
#error simdjson requires a compiler compliant with the C++11 standard #error simdjson requires a compiler compliant with the C++11 standard
#endif #endif
#ifndef SIMDJSON_IF_CONSTEXPR
#if SIMDJSON_CPLUSPLUS17
#define SIMDJSON_IF_CONSTEXPR if constexpr
#else
#define SIMDJSON_IF_CONSTEXPR if
#endif
#endif
#endif // SIMDJSON_COMPILER_CHECK_H #endif // SIMDJSON_COMPILER_CHECK_H
+1 -13
View File
@@ -1,11 +1,7 @@
#ifndef SIMDJSON_DOM_H #ifndef SIMDJSON_DOM_H
#define SIMDJSON_DOM_H #define SIMDJSON_DOM_H
#include "simdjson/base.h" #include "simdjson/dom/base.h"
SIMDJSON_PUSH_DISABLE_WARNINGS
SIMDJSON_DISABLE_UNDESIRED_WARNINGS
#include "simdjson/dom/array.h" #include "simdjson/dom/array.h"
#include "simdjson/dom/document_stream.h" #include "simdjson/dom/document_stream.h"
#include "simdjson/dom/document.h" #include "simdjson/dom/document.h"
@@ -14,22 +10,14 @@ SIMDJSON_DISABLE_UNDESIRED_WARNINGS
#include "simdjson/dom/parser.h" #include "simdjson/dom/parser.h"
#include "simdjson/dom/serialization.h" #include "simdjson/dom/serialization.h"
// Deprecated API
#include "simdjson/dom/jsonparser.h"
#include "simdjson/dom/parsedjson.h"
#include "simdjson/dom/parsedjson_iterator.h"
// Inline functions // Inline functions
#include "simdjson/dom/array-inl.h" #include "simdjson/dom/array-inl.h"
#include "simdjson/dom/document_stream-inl.h" #include "simdjson/dom/document_stream-inl.h"
#include "simdjson/dom/document-inl.h" #include "simdjson/dom/document-inl.h"
#include "simdjson/dom/element-inl.h" #include "simdjson/dom/element-inl.h"
#include "simdjson/dom/object-inl.h" #include "simdjson/dom/object-inl.h"
#include "simdjson/dom/parsedjson_iterator-inl.h"
#include "simdjson/dom/parser-inl.h" #include "simdjson/dom/parser-inl.h"
#include "simdjson/internal/tape_ref-inl.h" #include "simdjson/internal/tape_ref-inl.h"
#include "simdjson/dom/serialization-inl.h" #include "simdjson/dom/serialization-inl.h"
SIMDJSON_POP_DISABLE_WARNINGS
#endif // SIMDJSON_DOM_H #endif // SIMDJSON_DOM_H
+9 -5
View File
@@ -1,11 +1,15 @@
#ifndef SIMDJSON_INLINE_ARRAY_H #ifndef SIMDJSON_ARRAY_INL_H
#define SIMDJSON_INLINE_ARRAY_H #define SIMDJSON_ARRAY_INL_H
// Inline implementations go in here. #include <utility>
#include "simdjson/dom/base.h"
#include "simdjson/dom/array.h" #include "simdjson/dom/array.h"
#include "simdjson/dom/element.h" #include "simdjson/dom/element.h"
#include <utility> #include "simdjson/error-inl.h"
#include "simdjson/internal/tape_ref-inl.h"
#include <limits>
namespace simdjson { namespace simdjson {
@@ -170,4 +174,4 @@ static_assert(std::ranges::sized_range<simdjson::simdjson_result<simdjson::dom::
#endif // SIMDJSON_EXCEPTIONS #endif // SIMDJSON_EXCEPTIONS
#endif // defined(__cpp_lib_ranges) #endif // defined(__cpp_lib_ranges)
#endif // SIMDJSON_INLINE_ARRAY_H #endif // SIMDJSON_ARRAY_INL_H
+5 -11
View File
@@ -1,21 +1,12 @@
#ifndef SIMDJSON_DOM_ARRAY_H #ifndef SIMDJSON_DOM_ARRAY_H
#define SIMDJSON_DOM_ARRAY_H #define SIMDJSON_DOM_ARRAY_H
#include "simdjson/common_defs.h" #include "simdjson/dom/base.h"
#include "simdjson/error.h"
#include "simdjson/internal/tape_ref.h" #include "simdjson/internal/tape_ref.h"
namespace simdjson { namespace simdjson {
namespace internal {
template<typename T>
class string_builder;
}
namespace dom { namespace dom {
class document;
class element;
/** /**
* JSON array. * JSON array.
*/ */
@@ -28,11 +19,14 @@ public:
public: public:
using value_type = element; using value_type = element;
using difference_type = std::ptrdiff_t; using difference_type = std::ptrdiff_t;
using pointer = void;
using reference = value_type;
using iterator_category = std::forward_iterator_tag;
/** /**
* Get the actual value * Get the actual value
*/ */
inline value_type operator*() const noexcept; inline reference operator*() const noexcept;
/** /**
* Get the next value. * Get the next value.
* *

Some files were not shown because too many files have changed in this diff Show More