Compare commits

...

198 Commits

Author SHA1 Message Date
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
Daniel Lemire 92174c927d New release 2023-06-15 09:21:07 -04:00
Ng Yong Xiang b399c0165e Add comma separated value parsing as an option in iterate_many (#2016)
* Add comma separated value parsing

* Fix failing tests

* Make tests work for exceptions

* Fix test

* Fix try catch making test fail

---------

Co-authored-by: Yong Xiang Ng <yxng@drwholdings.com>
2023-06-15 09:11:14 -04:00
Daniel Lemire 445ae024ba fix: bug identified by Yagiz Nizipli (#2019) 2023-06-15 09:10:13 -04:00
Daniel Lemire 65f9822542 Adding tests for issue 2017 (#2018) 2023-06-07 09:57:28 -04:00
Daniel Lemire 74bb7b2533 Adding popcnt 2023-06-05 09:04:36 -04:00
Daniel Lemire fd97288561 Adding popcnt. 2023-06-02 20:33:15 -04:00
Daniel Lemire 1da0d8ac65 Making sure popcnt is included 2023-06-02 20:32:54 -04:00
Daniel Lemire 85661a2901 Some systems release without NDEBUG set, let us not assert in these cases. (#2014) 2023-06-01 16:18:36 -04:00
Daniel Lemire 3fcdb65d88 Update README.md 2023-05-26 09:26:17 -04:00
Daniel Lemire 8b00d91a2c More documentation. (#2011) 2023-05-26 09:23:21 -04:00
Daniel Lemire 7db3f97ba8 Adding CXX 20 to CI (#2005)
* Adding CXX 20 to CI

* side-stepping new CXX 20 guard.

* Going another way

* Saving.

* Explicit.

* Saving...

---------

Co-authored-by: Daniel Lemire <dlemire@lemire.me>
2023-05-26 09:23:02 -04:00
Daniel Lemire 412a8f7c4d Removing iso header. (#2009)
* Removing iso header.

* Fix.

* Another one.

* Caught another one.

---------

Co-authored-by: Daniel Lemire <dlemire@lemire.me>
2023-05-23 16:19:21 -04:00
Daniel Lemire d4b31c9feb Update README.md 2023-05-23 16:16:26 -04:00
Daniel Lemire ecdcf276b2 Update README.md 2023-05-23 16:15:13 -04:00
Daniel Lemire 6d92563280 Fixing issue 1943 (#2006)
* Fixing issue 1943

* Tweaking.
2023-05-23 11:15:22 -04:00
Daniel Lemire 0998233d58 More documentation. (#2007) 2023-05-23 11:15:07 -04:00
Daniel Lemire cb735818ec Document key queries. (#2008) 2023-05-23 11:14:55 -04:00
Daniel Lemire 41ee548e3f Adding godbolt examples. (#2010)
* Adding godbolt examples.

* Updating the examples.
2023-05-23 11:14:41 -04:00
Ng Yong Xiang e9d5d5088a Introduce logging levels for conditional logging and log key for NO_SUCH_FIELD error (#2004)
* Add info and error logging

* Add tests for error logging

* Add logging for missing field

* Update docs for logging usage

* Fix style and pass by ref for string format args

* Make log_level explicit and simplify get log level from env

* Make log level int32_t

* Format enum class

* Fix ci

* Move enum to header

* Fix compilation for noexception build in test case

* Disable warnings and putenv

---------

Co-authored-by: Yong Xiang Ng <yxng@drwholdings.com>
2023-05-22 12:58:55 -04:00
Daniel Lemire 78151e80e5 Update README.md 2023-05-16 12:49:49 -04:00
Daniel Lemire 083a5d7351 Update README.md 2023-05-15 15:03:11 -04:00
Daniel Lemire 25fcc8b432 Version bump. 2023-05-14 17:18:01 -04:00
Daniel Lemire a9c120f779 Directly check altivec macro. (#2002) 2023-05-14 17:17:10 -04:00
Daniel Lemire b1487e34c3 Adding more PPC64 testing. (#2001) 2023-05-14 16:11:49 -04:00
Daniel Lemire 2a68a32012 Checking OS support for AVX-512 (#1998)
* Adding support for AVX-512 on macOS.

* Fix.

* Fix.

* Minor fix

* Setting the variable to zero.

* Fixing include

* Checking if the OS supports AVX-512

* Tweaking.

---------

Co-authored-by: Daniel Lemire <dlemire@lemire.me>
2023-05-12 19:25:02 -04:00
Daniel Lemire 21a2ccaeb8 Another fun one 2023-05-05 22:12:59 -04:00
Daniel Lemire 6cbb6ac89b On ARM processors, rapidjson may struggle. Let us help it out. (#1996) 2023-05-05 21:42:37 -04:00
Dirk Stolle e9f0f1bb9b Mention IceLake in documentation about implementation selection. (#1995)
Since the creation of the IceLake implementation there are now
four available implementations on Intel/AMD x64 processors.
2023-04-28 21:29:01 -04:00
Serge Aleynikov 7ef1ebd4fb Add Erlang bindings (#1994) 2023-04-28 09:54:49 -04:00
Daniel Lemire 8de540e267 Update README.md 2023-04-27 14:27:05 -04:00
Daniel Lemire ebc51fbd1a Update bug_report.md 2023-04-24 08:05:26 -04:00
Daniel Lemire 84a31c1615 Update bug_report.md 2023-04-23 12:06:47 -04:00
Daniel Lemire f77ac963f4 Trying the undefined behaviour sanitizer (#1988)
* Trying the undefined behaviour sanitizer

* Trimming quiet
2023-04-23 11:50:05 -04:00
pjuhasz ae3d912f8d Add link to Perl binding (JSON::SIMD) (#1991)
Co-authored-by: Peter Juhasz <juhasz.peter@uhusystems.com>
2023-04-23 10:37:56 -04:00
Daniel Lemire abf3d7d440 Slightly safer linux counters 2023-04-21 13:26:49 -04:00
Daniel Lemire 3c313b8530 Removing old file. 2023-04-13 11:52:02 -04:00
Dirk Stolle f435fddda1 update string_view lite to version 1.7.0 (#1984)
This is the header as seen for the tag v1.7.0,
commit 7b1867b7c08f9ac010fb8b9dae79ff8c8359bafb, on
<https://github.com/martinmoene/string-view-lite>.
2023-04-11 13:58:38 -04:00
Daniel Lemire 14d927128b New release 2023-04-08 16:13:48 -04:00
Daniel Lemire 48152a0326 Fix for issue 1981 (#1982)
* Fix

* Rewording.

* Doing it differently.
2023-04-08 16:11:40 -04:00
Daniel Lemire b5cf53232c More documentation. 2023-04-06 10:52:18 -04:00
Daniel Lemire b3d0b732e6 Update README.md 2023-04-04 14:22:12 -04:00
Daniel Lemire 3c29f40f2f Trying to verify issue 1979 (#1980) 2023-04-04 11:03:37 -04:00
Daniel Lemire 4a89d79984 Guarding the benchmarks. 2023-04-01 18:39:11 -04:00
Daniel Lemire 9cb639dcd7 Update basics.md 2023-03-30 12:35:38 -04:00
Daniel Lemire 4699dd0ce2 Update basics.md 2023-03-30 10:49:19 -04:00
Daniel Lemire cfd337bb50 This PR adds an 'at_end()' method. (#1978)
* This PR adds an 'at_end()' method.

* Adding 1111 }

* Tweaking test.
2023-03-30 10:47:13 -04:00
Daniel Lemire 9bef628982 It is no longer necessary to check separately for trailing content. 2023-03-24 20:04:04 -04:00
Daniel Lemire 59025bc8b1 Avoiding the issue where doc.get_value().get_object() differs from doc.get_object() in how errors are reported. (#1975)
* Avoiding the issue where doc.get_value().get_object() differs from doc.get_object() in how errors are reported.

* Minor tweaks
2023-03-24 12:44:18 -04:00
Daniel Lemire ffe96dde19 Update HACKING.md 2023-03-22 09:02:24 -04:00
Daniel Lemire f9664cf184 Update HACKING.md 2023-03-22 08:56:12 -04:00
Daniel Lemire 830323f383 Update HACKING.md 2023-03-22 08:55:26 -04:00
Daniel Lemire eb8e15d9c0 Update HACKING.md 2023-03-22 08:53:44 -04:00
Daniel Lemire 3571f3a8d0 Additional documentation. 2023-03-18 16:38:16 -04:00
Daniel Lemire 4b13020d65 Patch release 2023-03-13 21:44:34 -04:00
Daniel Lemire 75c6c950e5 Ok. 2023-03-13 21:26:32 -04:00
Daniel Lemire 5ad7698af1 ... 2023-03-13 17:07:25 -04:00
Daniel Lemire f6f359d3eb Very silly. 2023-03-13 17:05:53 -04:00
Daniel Lemire 185e157e0c Silencing the stupid compiler warnings. 2023-03-13 16:06:10 -04:00
Daniel Lemire 3f3f6cde7c Bad compiler 2023-03-13 13:33:20 -04:00
Daniel Lemire 005054916d Bad compiler 2023-03-13 13:02:01 -04:00
Daniel Lemire 338224849d Disabling memory sanitizer with one function. Might help with issue 1965 (#1966)
* Might help with issue 1965

* Fix macro

* Adding test.

* Stupid compiler

* Silly compiler

* Stupid compilers

* Unnecessary fixes

* Update developer-options.cmake
2023-03-13 12:34:47 -04:00
Ashot Vardanian ada52641b4 Fix: Defining maximal DOM capacity (#1970) 2023-03-13 12:33:37 -04:00
Daniel Lemire ede9d57f22 Adding tests with _GLIBCXX_ASSERTIONS (#1969)
* Allowing users to specify -D_GLIBCXX_ASSERTIONS

* Adding CI tests for GLIBCXX_ASSERTIONS

* Adding curly brackets.
2023-03-13 12:32:43 -04:00
Daniel Lemire 7bf33f6c8a Bad compiler 2023-03-13 12:29:01 -04:00
Daniel Lemire d62b789cb3 More curly. 2023-03-13 10:49:15 -04:00
Daniel Lemire 33dbd44098 Better way to put -Og in debug mode (#1967)
* Better way to put -Og in debug mode

* Silly compiler

* Stupid compiler.

* Stupid compiler.

* Silly compiler
2023-03-13 10:11:33 -04:00
Daniel Lemire e0dcf8adc9 Silly compiler 2023-03-12 20:57:45 -04:00
Daniel Lemire 34dcd33a88 Patch. 2023-03-09 11:24:06 -05:00
Daniel Lemire 17a1a8e187 Adding -Og to debug builds. (#1964)
* Adding -Og to debug builds.

* Stupid compiler.

* bad, bad, bad compiler
2023-03-09 11:14:42 -05:00
Daniel Lemire 77ad00b63c Producing a minor patch release 2023-03-09 11:13:01 -05:00
Daniel Lemire 25e7f1765a Various tweaks. 2023-03-09 10:42:23 -05:00
Daniel Lemire 8d01255ceb Update basics.md 2023-03-09 08:27:32 -05:00
Daniel Lemire 8ec016b093 Update README.md 2023-03-08 15:30:52 -05:00
Daniel Lemire 9e726b9856 Removing obsolete badge 2023-03-08 14:50:37 -05:00
Daniel Lemire 312f1f26d3 Now obsolete. 2023-03-08 14:50:06 -05:00
Daniel Lemire ba50571d66 Merge branch 'master' of github.com:simdjson/simdjson 2023-03-06 16:05:10 -05:00
Daniel Lemire 4a587cb898 Adding guards. 2023-03-06 16:04:42 -05:00
Daniel Lemire bdf9123c92 Update README.md 2023-03-06 11:08:56 -05:00
Dominik Lohmann 6e4c29b7c5 Fix export component for simdjsonTargets.cmake (#1962)
This fixes a bug that caused simdjsonTargets.cmake not to be included in
CPack-generated packages, which—unlike `cmake --install`—does not
pick up this mislabeled install component.

I git-grepped through the code base, after this change all components
are either `simdjson_Development` or `simdjson_Runtime`.
2023-03-04 17:34:40 -05:00
Daniel Lemire ec0b48b772 Version bump. 2023-03-02 14:27:49 -05:00
Daniel Lemire d65acbd47b Tuning documentation. 2023-03-02 09:39:35 -05:00
Daniel Lemire 75240ad8e1 Update basics.md 2023-03-01 19:05:45 -05:00
Daniel Lemire 3efb44dc0f Adding link 2023-03-01 19:03:03 -05:00
Daniel Lemire 5c5cd5b42d [skip ci] rephrasing. 2023-03-01 10:08:00 -05:00
Daniel Lemire 12a1b6db53 This adds some examples to the documentation. (#1959)
* This adds some examples to the documentation.

* Fix
2023-02-28 22:59:42 -05:00
Daniel Lemire 37e87f6f99 Adding support for wobbly strings to On Demand and lossy trancoding from escaped (with replacement) (#1947)
* Adding support for wobbly strings.

* Minor tweak.

* Adopt substitution code point.

* Lossy

* Patching
2023-02-28 22:56:44 -05:00
wanweiqiangintel cd13b02bf0 add UTF-8 validation flag (#1957) 2023-02-28 09:47:08 -05:00
Daniel Lemire 624174d916 Minor doc. tweaks. 2023-02-22 21:14:15 -05:00
Daniel Lemire 8a247f1321 Patch release. 2023-02-22 20:39:31 -05:00
Daniel Lemire 7aa35bffd3 Fixing support for windows ARM64 (#1955)
* Fixing Windows ARM64 support

* Updating the singleheader files.
2023-02-22 20:34:51 -05:00
Rawley d6c910686b Update README.md (#1953) 2023-02-13 21:11:05 -05:00
Daniel Lemire 22cc523fd4 Patching release script. 2023-02-06 19:11:52 -05:00
Daniel Lemire 3177cd1b5d Fix. 2023-02-06 19:08:11 -05:00
Daniel Lemire 63d9ce3c58 Patch release. 2023-02-06 18:31:02 -05:00
Daniel Lemire 8e8180560d Fix for issue 1950 (#1951) 2023-02-06 18:28:54 -05:00
Daniel Lemire 1594af5d5d Tweak. 2023-02-06 08:51:11 -05:00
Dirk Stolle b207338365 Remove trailing whitespace in README.md (#1949)
This should make the whitespace test pass again.
2023-01-31 17:53:35 -05:00
Daniel Lemire 68be9c2170 Update README.md 2023-01-30 16:17:42 -05:00
Daniel Lemire 5347771091 Update documentation.yml 2023-01-30 15:14:27 -05:00
Daniel Lemire 8bf8315651 Update README.md 2023-01-30 14:50:06 -05:00
Daniel Lemire 269ae7ad6b [skip ci] stupid mistake 2023-01-30 14:37:40 -05:00
Daniel Lemire 2aa91f741f [skip ci] new doc runner 2023-01-30 14:29:48 -05:00
Daniel Lemire 5430544bbb [skip ci] improving documentation. (#1948) 2023-01-30 14:27:35 -05:00
Daniel Lemire 7b55f16682 Trying s390x in CI (#1945)
* Trying s390x

* Providing big endian testing.

* adding token.

* Fixing branch
2023-01-27 11:34:00 -05:00
Daniel Lemire d8fec59e85 Safer add-dependency script. (#1946) 2023-01-26 22:40:26 -05:00
Daniel Lemire 57b6034a0c Let verbose 2023-01-26 21:12:23 -05:00
Daniel Lemire 7500d7bb4f Patching. 2023-01-25 22:19:40 -05:00
310 changed files with 109276 additions and 20489 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
+9 -7
View File
@@ -12,24 +12,26 @@ Before submitting an issue, please ensure that you have read the documentation:
* Basics is an overview of how to use simdjson and its APIs: https://github.com/simdjson/simdjson/blob/master/doc/basics.md * Basics is an overview of how to use simdjson and its APIs: https://github.com/simdjson/simdjson/blob/master/doc/basics.md
* Performance shows some more advanced scenarios and how to tune for them: https://github.com/simdjson/simdjson/blob/master/doc/performance.md * Performance shows some more advanced scenarios and how to tune for them: https://github.com/simdjson/simdjson/blob/master/doc/performance.md
* Contributing: https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md * Contributing: https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md
* We follow the [JSON specification as described by RFC 8259](https://www.rfc-editor.org/rfc/rfc8259.txt) (T. Bray, 2017). * We follow the [JSON specification as described by RFC 8259](https://www.rfc-editor.org/rfc/rfc8259.txt) (T. Bray, 2017). If you wish to support features that are not part of RFC 8259, then you should not refer to your issue as a bug.
**Describe the bug** **Describe the bug**
A clear and concise description of what the bug is. A clear and concise description of what the bug is. A bug is a failure to build with normal compiler settings or a misbehaviour: when running the code, you get a result that differs from the expected result from our documentation.
A compiler or static-analyzer warning is not a bug. A compiler or static-analyzer warning is not a bug. It is possible with tools such as Visual Studio to require that rarely enabled warnings are considered errors. Do not report such cases as bugs. We do accept pull requests if you want to silence warnings issued by code analyzers, however.
We are committed to providing good documentation. We accept the lack of documentation or a misleading documentation as a bug (a 'documentation bug'). We are committed to providing good documentation. We accept the lack of documentation or a misleading documentation as a bug (a 'documentation bug').
An unexpected poor software performance can be accepted as a bug (a 'performance bug').
We accept the identification of an issue by a sanitizer or some checker tool (e.g., valgrind) as a bug, but you must first ensure that it is not a false positive. We accept the identification of an issue by a sanitizer or some checker tool (e.g., valgrind) as a bug, but you must first ensure that it is not a false positive.
We recommend that you run your tests using different optimization levels. We recommend that you run your tests using different optimization levels. In particular, we recommend your run tests with the simdjson library and you code compiled in debug mode. The simdjson then sets the SIMDJSON_DEVELOPMENT_CHECKS macro to 1, and this triggers additional checks on your code and on the internals of the library. If possible, we recommend that you run tests with sanitizers (e.g., see [No more leaks with sanitize flags in gcc and clang](https://lemire.me/blog/2016/04/20/no-more-leaks-with-sanitize-flags-in-gcc-and-clang/)). You can compile the library with sanitizers for debugging purposes (e.g., set SIMDJSON_SANITIZE to ON using CMake), but you should also turn on sanitizers on your own code. You may also use tools like valgrind or the commercial equivalent.
Before reporting a bug, please ensure that you have read our documentation. Before reporting a bug, please ensure that you have read our documentation.
**To Reproduce** **To Reproduce**
Steps to reproduce the behaviour: provide a code sample if possible. Steps to reproduce the behaviour: provide a code sample if possible. Please provide a complete test with data. Remember that a bug is either a failure to build or an unexpected result when running the code.
If we cannot reproduce the issue, then we cannot address it. Note that a stack trace from your own program is not enough. A sample of your source code is insufficient: please provide a complete test for us to reproduce the issue. Please reduce the issue: use as small and as simple an example of the bug as possible. If we cannot reproduce the issue, then we cannot address it. Note that a stack trace from your own program is not enough. A sample of your source code is insufficient: please provide a complete test for us to reproduce the issue. Please reduce the issue: use as small and as simple an example of the bug as possible.
@@ -47,10 +49,10 @@ It is fine to report bugs against our main branch, but if that is what you are d
- 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.
**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**
If you plan to contribute to simdjson, please read our If you plan to contribute to simdjson, please read our guide:
* 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
+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
+1 -1
View File
@@ -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"
+34
View File
@@ -0,0 +1,34 @@
name: Doxygen GitHub Pages
on:
push:
branches:
- master
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
permissions:
contents: write
pages: write
id-token: write
jobs:
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Doxygen
run: sudo apt-get install doxygen graphviz -y
- run: mkdir docs
- name: Install theme
run: ./tools/prepare_doxygen.sh
- name: Generate Doxygen Documentation
run: doxygen
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: doc/api/html
+4 -3
View File
@@ -34,6 +34,7 @@ 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
@@ -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
+13 -2
View File
@@ -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
@@ -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@v3
- 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
+29
View File
@@ -0,0 +1,29 @@
name: Ubuntu ppc64le (GCC 11)
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: uraimo/run-on-arch-action@v2
name: Test
id: runcmd
with:
arch: ppc64le
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
+29
View File
@@ -0,0 +1,29 @@
name: Ubuntu s390x (GCC 11)
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: uraimo/run-on-arch-action@v2
name: Test
id: runcmd
with:
arch: s390x
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
-29
View File
@@ -1,29 +0,0 @@
name: Performance check on Ubuntu 18.04 CI (GCC 7)
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
ubuntu-build:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Use cmake
run: |
mkdir build &&
cd build &&
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_ENABLE_DOM_CHECKPERF=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
cmake --build . --target checkperf &&
ctest --output-on-failure -R checkperf ubuntu18-checkperf.yml
-25
View File
@@ -1,25 +0,0 @@
name: Ubuntu 18.04 CI (GCC 7) with Thread Sanitizer
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-18.04
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Use cmake
run: |
mkdir build &&
cd build &&
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_SANITIZE_THREADS=ON .. &&
cmake --build . --target document_stream_tests --target ondemand_document_stream_tests --target parse_many_test &&
ctest --output-on-failure -R parse_many_test &&
ctest --output-on-failure -R document_stream_tests
-25
View File
@@ -1,25 +0,0 @@
name: Ubuntu 18.04 CI (GCC 7)
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-18.04
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Use cmake
run: |
mkdir build &&
cd build &&
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
cmake --build . &&
ctest -j --output-on-failure -LE explicitonly &&
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
+2 -2
View File
@@ -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 &&
+2 -2
View File
@@ -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 &&
+2 -2
View File
@@ -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 &&
+22 -3
View File
@@ -3,7 +3,7 @@ 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]')
@@ -14,10 +14,29 @@ jobs:
with: with:
path: dependencies/.cache path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }} key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Use cmake - name: Use cmake with address sanitizer
run: | run: |
mkdir builddebug && mkdir builddebug &&
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@v3
- uses: actions/cache@v3
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
ctest --output-on-failure -LE explicitonly -j
- name: Use cmake with undefined sanitizer
run: |
mkdir 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 --build . &&
ctest --output-on-failure -LE explicitonly -j
+16 -2
View File
@@ -14,19 +14,33 @@ jobs:
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 -3
View File
@@ -14,12 +14,10 @@ jobs:
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
+1 -3
View File
@@ -14,12 +14,10 @@ jobs:
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
+33
View File
@@ -0,0 +1,33 @@
name: Ubuntu 22.04 CI (GCC 12, CXX 20)
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@v3
- uses: actions/cache@v3
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Use cmake
run: |
mkdir 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 .. &&
cmake --build . &&
ctest --output-on-failure -LE explicitonly -j &&
cd .. &&
mkdir 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 .. &&
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 build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../build/destination .. && cmake --build .
+1 -1
View File
@@ -22,4 +22,4 @@ jobs:
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
@@ -1,5 +1,4 @@
name: Ubuntu 18.04 CI (LLVM 7) name: Ubuntu 22.04 CI GCC 12 with GLIBCXX_ASSERTIONS
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
@@ -7,25 +6,19 @@ 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-18.04 runs-on: ubuntu-22.04
env:
CC: clang-7
CXX: clang++-7
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- 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 7 - name: Install gcc12
run: | run: sudo apt-get install -y g++-12
sudo apt update
sudo apt install clang-7
- name: Use cmake - name: Use cmake
run: | run: |
mkdir build && mkdir build &&
cd build && cd build &&
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. && CXX=g++-12 cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GLIBCXX_ASSERTIONS=ON -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON .. &&
cmake --build . && cmake --build . &&
ctest -j --output-on-failure -LE explicitonly ctest . -E avoid_
@@ -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,7 +7,7 @@ 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@v3
- uses: actions/cache@v3 - uses: actions/cache@v3
+16 -2
View File
@@ -14,19 +14,33 @@ jobs:
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 &&
+44
View File
@@ -0,0 +1,44 @@
name: VS17-CI CXX20
on: [push, pull_request]
jobs:
ci:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
name: windows-vs17
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
include:
- {gen: Visual Studio 17 2022, arch: Win32, shared: ON}
- {gen: Visual Studio 17 2022, arch: Win32, shared: OFF}
- {gen: Visual Studio 17 2022, arch: x64, shared: ON}
- {gen: Visual Studio 17 2022, arch: x64, shared: OFF}
steps:
- name: checkout
uses: actions/checkout@v3
- name: Configure
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
- name: Build Debug
run: cmake --build build --config Debug --verbose
- name: Build Release
run: cmake --build build --config Release --verbose
- name: Run Release tests
run: |
cd build
ctest -C Release -LE explicitonly --output-on-failure
- name: Run Debug tests
run: |
cd build
ctest -C Debug -LE explicitonly --output-on-failure
- name: Install
run: |
cmake --install build --config Release
- name: Test Installation
run: |
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -B build_install_test tests/installation_tests/find
cmake --build build_install_test --config Release
+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.
+3 -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",
@@ -96,6 +97,7 @@
"future": "cpp", "future": "cpp",
"queue": "cpp", "queue": "cpp",
"shared_mutex": "cpp", "shared_mutex": "cpp",
"ranges": "cpp" "ranges": "cpp",
"span": "cpp"
} }
} }
+57 -10
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.1.0 VERSION 3.3.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 "15.0.0" CACHE STRING "simdjson library version") set(SIMDJSON_LIB_VERSION "16.0.0" CACHE STRING "simdjson library version")
set(SIMDJSON_LIB_SOVERSION "15" CACHE STRING "simdjson library soversion") set(SIMDJSON_LIB_SOVERSION "16" 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
@@ -95,6 +106,21 @@ if(
) )
endif() endif()
# GCC and Clang have horrendous Debug builds when using SIMD.
# A common fix is to use '-Og' instead.
# bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54412
if(
(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR
CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR
CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
)
message(STATUS "Adding -Og to compile flag")
simdjson_add_props(
target_compile_options PRIVATE
$<$<CONFIG:DEBUG>:-Og>
)
endif()
if(SIMDJSON_ENABLE_THREADS) if(SIMDJSON_ENABLE_THREADS)
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
simdjson_add_props(target_link_libraries PUBLIC Threads::Threads) simdjson_add_props(target_link_libraries PUBLIC Threads::Threads)
@@ -102,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 ----
@@ -123,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(
@@ -149,9 +177,23 @@ install(
EXPORT simdjsonTargets EXPORT simdjsonTargets
NAMESPACE simdjson:: NAMESPACE simdjson::
DESTINATION "${SIMDJSON_INSTALL_CMAKEDIR}" DESTINATION "${SIMDJSON_INSTALL_CMAKEDIR}"
COMPONENT example_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}")
@@ -188,11 +230,14 @@ endif()
# ---- Developer mode extras ---- # ---- Developer mode extras ----
if(is_top_project AND NOT SIMDJSON_DEVELOPER_MODE)
message(STATUS "Building only the library. Advanced users and contributors may want to turn SIMDJSON_DEVELOPER_MODE to ON, e.g., via -D SIMDJSON_DEVELOPER_MODE=ON.")
elseif(SIMDJSON_DEVELOPER_MODE AND NOT is_top_project)
message(AUTHOR_WARNING "Developer mode in simdjson is intended for the developers of simdjson")
endif()
if(NOT SIMDJSON_DEVELOPER_MODE) if(NOT SIMDJSON_DEVELOPER_MODE)
message(STATUS "Building only the library. Advanced users may want to turn SIMDJSON_DEVELOPER_MODE to ON, e.g., via -D SIMDJSON_DEVELOPER_MODE=ON.")
return() return()
elseif(NOT is_top_project)
message(AUTHOR_WARNING "Developer mode is intended for developers of simdjson")
endif() endif()
simdjson_apply_props(simdjson-internal-flags) simdjson_apply_props(simdjson-internal-flags)
@@ -233,7 +278,9 @@ add_subdirectory(singleheader)
# #
add_subdirectory(tests) add_subdirectory(tests)
add_subdirectory(examples) add_subdirectory(examples)
add_subdirectory(benchmark) if(CMAKE_SIZEOF_VOID_P EQUAL 8) # we only include the benchmarks on 64-bit systems.
add_subdirectory(benchmark)
endif()
add_subdirectory(fuzz) add_subdirectory(fuzz)
# #
+11 -5
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.1.0" PROJECT_NUMBER = "3.3.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
@@ -829,7 +829,7 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched. # Note: If this tag is empty the current directory is searched.
INPUT = doc include INPUT = doc include/simdjson include/simdjson/dom include/simdjson/generic
# This tag can be used to specify the character encoding of the source files # This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@@ -1246,7 +1246,10 @@ HTML_STYLESHEET =
# list). For an example see the documentation. # list). For an example see the documentation.
# This tag requires that the tag GENERATE_HTML is set to YES. # This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_STYLESHEET =
HTML_EXTRA_STYLESHEET = theme/doxygen-awesome.css \
theme/doxygen-awesome-sidebar-only.css \
theme/doxygen-awesome-sidebar-only-darkmode-toggle.css
# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
# other source files which should be copied to the HTML output directory. Note # other source files which should be copied to the HTML output directory. Note
@@ -1256,7 +1259,10 @@ HTML_EXTRA_STYLESHEET =
# files will be copied as-is; there are no commands or markers available. # files will be copied as-is; there are no commands or markers available.
# This tag requires that the tag GENERATE_HTML is set to YES. # This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_FILES = HTML_EXTRA_FILES = theme/doxygen-awesome-darkmode-toggle.js \
theme/doxygen-awesome-interactive-toc.js \
theme/doxygen-awesome-fragment-copy-button.js \
theme/doxygen-awesome-paragraph-link.js
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
# will adjust the colors in the style sheet and background images according to # will adjust the colors in the style sheet and background images according to
@@ -1543,7 +1549,7 @@ DISABLE_INDEX = NO
# The default value is: NO. # The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES. # This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_TREEVIEW = NO GENERATE_TREEVIEW = YES
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
# doxygen will group on one line in the generated HTML documentation. # doxygen will group on one line in the generated HTML documentation.
+49 -18
View File
@@ -1,3 +1,4 @@
Hacking simdjson Hacking simdjson
================ ================
@@ -5,6 +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)
- [Developer mode](#developer-mode)
- [Directory Structure and Source](#directory-structure-and-source)
- [Runtime Dispatching](#runtime-dispatching)
- [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 Windows using Visual Studio 2019 or better)](#usage-cmake-on-64-bit-windows-using-visual-studio-2019-or-better)
- [Various References](#various-references)
Build Quickstart
------------------------------
```bash
mkdir build
cd build
cmake -D SIMDJSON_DEVELOPER_MODE=ON ..
cmake --build .
```
Design notes Design notes
------------------------------ ------------------------------
@@ -52,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>` namesapce. 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.
@@ -193,7 +222,7 @@ point it gets included (but only once per header). singleheader/simdjson.cpp is
src/simdjson.cpp the same way, except files under generic/ may be included and copy/pasted multiple src/simdjson.cpp the same way, except files under generic/ may be included and copy/pasted multiple
times. times.
### Usage (CMake on 64-bit platforms like Linux, FreeBSD or macOS) ## Usage (CMake on 64-bit platforms like Linux, FreeBSD or macOS)
Requirements: In addition to git, we require a recent version of CMake as well as bash. Requirements: In addition to git, we require a recent version of CMake as well as bash.
@@ -256,7 +285,9 @@ Note that the name of directory (`build`) is arbitrary, you can name it as you w
### Usage (CMake on 64-bit Windows using Visual Studio 2019) ## Usage (CMake on 64-bit Windows using Visual Studio 2019 or better)
Recent versions of Visual Studio support CMake natively, [please refer to the Visual Studio documentation](https://learn.microsoft.com/en-us/cpp/build/cmake-projects-in-visual-studio?view=msvc-170).
We assume you have a common 64-bit Windows PC with at least Visual Studio 2019. We assume you have a common 64-bit Windows PC with at least Visual Studio 2019.
@@ -285,7 +316,7 @@ Furthermore, if you have installed LLVM clang on Windows, for example as a compo
- `cmake --build . -config Release` - `cmake --build . -config Release`
### Various References ## Various References
- [How to implement atoi using SIMD?](https://stackoverflow.com/questions/35127060/how-to-implement-atoi-using-simd) - [How to implement atoi using SIMD?](https://stackoverflow.com/questions/35127060/how-to-implement-atoi-using-simd)
- [Parsing JSON is a Minefield 💣](http://seriot.ch/parsing_json.php) - [Parsing JSON is a Minefield 💣](http://seriot.ch/parsing_json.php)
+43 -26
View File
@@ -1,9 +1,9 @@
![Ubuntu 18.04 CI](https://github.com/simdjson/simdjson/workflows/Ubuntu%2018.04%20CI%20(GCC%207)/badge.svg)
[![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)
![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.org/api/3.0.0/index.html)
[![Doxygen Documentation](https://img.shields.io/badge/docs-doxygen-green.svg)](https://simdjson.github.io/simdjson/)
simdjson : Parsing gigabytes of JSON per second simdjson : Parsing gigabytes of JSON per second
=============================================== ===============================================
@@ -26,16 +26,39 @@ This library is part of the [Awesome Modern C++](https://awesomecpp.com) list.
Table of Contents Table of Contents
----------------- -----------------
* [Real-world usage](#real-world-usage)
* [Quick Start](#quick-start) * [Quick Start](#quick-start)
* [Documentation](#documentation) * [Documentation](#documentation)
* [Performance results](#performance-results) * [Performance results](#performance-results)
* [Real-world usage](#real-world-usage)
* [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)
* [Funding](#funding) * [Funding](#funding)
* [Contributing to simdjson](#contributing-to-simdjson) * [Contributing to simdjson](#contributing-to-simdjson)
* [License](#license) * [License](#license)
Real-world usage
----------------
- [ClickHouse](https://github.com/ClickHouse/ClickHouse)
- [Facebook/Meta Velox](https://velox-lib.io)
- [milvus](https://github.com/milvus-io/milvus)
- [Clang Build Analyzer](https://github.com/aras-p/ClangBuildAnalyzer)
- [Shopify HeapProfiler](https://github.com/Shopify/heap-profiler)
- [StarRocks](https://github.com/StarRocks/starrocks)
- [Microsoft FishStore](https://github.com/microsoft/FishStore)
- [Intel PCM](https://github.com/intel/pcm)
- [WatermelonDB](https://github.com/Nozbe/WatermelonDB)
- [Apache Doris](https://github.com/apache/doris)
- [Dgraph](https://github.com/dgraph-io/dgraph)
- [UJRPC](https://github.com/unum-cloud/ujrpc)
- [fastgltf](https://github.com/spnda/fastgltf)
- [vast](https://github.com/tenzir/vast)
- [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.
Quick Start Quick Start
----------- -----------
@@ -62,13 +85,13 @@ int main(void) {
ondemand::document tweets = parser.iterate(json); ondemand::document tweets = parser.iterate(json);
std::cout << uint64_t(tweets["search_metadata"]["count"]) << " results." << std::endl; std::cout << uint64_t(tweets["search_metadata"]["count"]) << " results." << std::endl;
} }
```
```
3. `c++ -o quickstart quickstart.cpp simdjson.cpp` 3. `c++ -o quickstart quickstart.cpp simdjson.cpp`
4. `./quickstart` 4. `./quickstart`
```
```
100 results. 100 results.
``` ```
Documentation Documentation
------------- -------------
@@ -79,7 +102,13 @@ Usage documentation is available:
* [Performance](doc/performance.md) shows some more advanced scenarios and how to tune for them. * [Performance](doc/performance.md) shows some more advanced scenarios and how to tune for them.
* [Implementation Selection](doc/implementation-selection.md) describes runtime CPU detection and * [Implementation Selection](doc/implementation-selection.md) describes runtime CPU detection and
how you can work with it. how you can work with it.
* [API](https://simdjson.org/api/1.0.0/annotated.html) contains the automatically generated API documentation. * [API](https://simdjson.github.io/simdjson/) contains the automatically generated API documentation.
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/98Kx9Kqjn)
* [simdjson examples with errors without exceptions](https://godbolt.org/z/PKG7GdbPo)
Performance results Performance results
------------------- -------------------
@@ -108,21 +137,6 @@ For NDJSON files, we can exceed 3 GB/s with [our multithreaded parsing function
Real-world usage
----------------
- [ClickHouse](https://github.com/ClickHouse/ClickHouse)
- [Clang Build Analyzer](https://github.com/aras-p/ClangBuildAnalyzer)
- [Shopify HeapProfiler](https://github.com/Shopify/heap-profiler)
- [StarRocks](https://github.com/StarRocks/starrocks)
- [Microsoft FishStore](https://github.com/microsoft/FishStore)
- [Intel PCM](https://github.com/intel/pcm)
- [WatermelonDB](https://github.com/Nozbe/WatermelonDB)
- [Apache Doris](https://github.com/apache/doris)
- [Dgraph](https://github.com/dgraph-io/dgraph)
If you are planning to use simdjson in a product, please work from one of our releases.
Bindings and Ports of simdjson Bindings and Ports of simdjson
------------------------------ ------------------------------
@@ -143,9 +157,12 @@ We distinguish between "bindings" (which just wrap the C++ code) and a port to a
- [simdjson-go](https://github.com/minio/simdjson-go): Go port using Golang assembly. - [simdjson-go](https://github.com/minio/simdjson-go): Go port using Golang assembly.
- [rcppsimdjson](https://github.com/eddelbuettel/rcppsimdjson): R bindings. - [rcppsimdjson](https://github.com/eddelbuettel/rcppsimdjson): R bindings.
- [simdjson_erlang](https://github.com/ChomperT/simdjson_erlang): erlang bindings. - [simdjson_erlang](https://github.com/ChomperT/simdjson_erlang): erlang bindings.
- [simdjsone](https://github.com/saleyn/simdjsone): erlang bindings.
- [lua-simdjson](https://github.com/FourierTransformer/lua-simdjson): lua bindings. - [lua-simdjson](https://github.com/FourierTransformer/lua-simdjson): lua bindings.
- [hermes-json](https://hackage.haskell.org/package/hermes-json): haskell bindings. - [hermes-json](https://hackage.haskell.org/package/hermes-json): haskell bindings.
- [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://metacpan.org/pod/JSON::SIMD): Perl bindings; fully-featured JSON module that uses simdjson for decoding.
About simdjson About simdjson
-------------- --------------
@@ -188,7 +205,7 @@ License
This code is made available under the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0.html). This code is made available under the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0.html).
Under Windows, we build some tools using the windows/dirent_portable.h file (which is outside our library code): it under the liberal (business-friendly) MIT license. Under Windows, we build some tools using the windows/dirent_portable.h file (which is outside our library code): it is under the liberal (business-friendly) MIT license.
For compilers that do not support [C++17](https://en.wikipedia.org/wiki/C%2B%2B17), we bundle the string-view library which is published under the [Boost license](http://www.boost.org/LICENSE_1_0.txt). Like the Apache license, the Boost license is a permissive license allowing commercial redistribution. For compilers that do not support [C++17](https://en.wikipedia.org/wiki/C%2B%2B17), we bundle the string-view library which is published under the [Boost license](http://www.boost.org/LICENSE_1_0.txt). Like the Apache license, the Boost license is a permissive license allowing commercial redistribution.
-69
View File
@@ -1,69 +0,0 @@
# 0.5
## Highlights
Performance
* Faster and simpler UTF-8 validation with the lookup4 algorithm https://github.com/simdjson/simdjson/pull/993
* We improved the performance of simdjson under Visual Studio by about 25%. Users will still get better performance with clang-cl (+30%) but the gap has been reduced. https://github.com/simdjson/simdjson/pull/1031
Code usability
* In `parse_many`, when parsing streams of JSON documetns, we give to the users runtime control as to whether threads are used (via the parser.threaded attribute). https://github.com/simdjson/simdjson/issues/925
* Prefixed public macros to avoid name clashes with other libraries. https://github.com/simdjson/simdjson/issues/1035
* Better documentation regarding package managers (brew, MSYS2, conan, apt, vcpkg, FreeBSD package manager, etc.).
* Better documentation regarding CMake usage.
Standards
* We improved standard compliance with respect to both the JSON RFC 8259 and JSON Pointer RFC 6901. We added the at_pointer method to nodes for standard-compliant JSON Pointer queries. The legacy `at(std::string_view)` method remains but is deprecated since it is not standard-compliant as per RFC 6901.
* We removed computed GOTOs without sacrificing performance thus improving the C++ standard compliance (since computed GOTOs are compiler-specific extensions).
* Better support for C++20 https://github.com/simdjson/simdjson/pull/1050
# 0.4
## Highlights
- Test coverage has been greatly improved and we have resolved many static-analysis warnings on different systems.
- We added a fast (8GB/s) minifier that works directly on JSON strings.
- We added fast (10GB/s) UTF-8 validator that works directly on strings (any strings, including non-JSON).
- The array and object elements have a constant-time size() method.
- Performance improvements to the API (type(), get<>()).
- The parse_many function (ndjson) has been entirely reworked. It now uses a single secondary thread instead of several new threads.
- We have introduced a faster UTF-8 validation algorithm (lookup3) for all kernels (ARM, x64 SSE, x64 AVX).
- C++11 support for older compilers and systems.
- FreeBSD support (and tests).
- We support the clang front-end compiler (clangcl) under Visual Studio.
- It is now possible to target ARM platforms under Visual Studio.
- The simdjson library will never abort or print to standard output/error.
# 0.3
## Highlights
- **Multi-Document Parsing:** Read a bundle of JSON documents (ndjson) 2-4x faster than doing it
individually. [API docs](https://github.com/simdjson/simdjson/blob/master/doc/basics.md#newline-delimited-json-ndjson-and-json-lines) / [Design Details](https://github.com/simdjson/simdjson/blob/master/doc/parse_many.md)
- **Simplified API:** The API has been completely revamped for ease of use, including a new JSON
navigation API and fluent support for error code *and* exception styles of error handling with a
single API. [Docs](https://github.com/simdjson/simdjson/blob/master/doc/basics.md#the-basics-loading-and-parsing-json-documents)
- **Exact Float Parsing:** Now simdjson parses floats flawlessly *without* any performance loss,
thanks to [great work by @michaeleisel and @lemire](https://github.com/simdjson/simdjson/pull/558).
[Blog Post](https://lemire.me/blog/2020/03/10/fast-float-parsing-in-practice/)
- **Even Faster:** The fastest parser got faster! With a [shiny new UTF-8 validator](https://github.com/simdjson/simdjson/pull/387)
and meticulously refactored SIMD core, simdjson 0.3 is 15% faster than before, running at 2.5 GB/s
(where 0.2 ran at 2.2 GB/s).
## Minor Highlights
- Fallback implementation: simdjson now has a non-SIMD fallback implementation, and can run even on
very old 64-bit machines.
- Automatic allocation: as part of API simplification, the parser no longer has to be preallocated--
it will adjust automatically when it encounters larger files.
- Runtime selection API: We've exposed simdjson's runtime CPU detection and implementation selection
as an API, so you can tell what implementation we detected and test with other implementations.
- Error handling your way: Whether you use exceptions or check error codes, simdjson lets you handle
errors in your style. APIs that can fail return simdjson_result<T>, letting you check the error
code before using the result. But if you are more comfortable with exceptions, skip the error code
and cast straight to T, and exceptions will be thrown automatically if an error happens. Use the
same API either way!
- Error chaining: We also worked to keep non-exception error-handling short and sweet. Instead of
having to check the error code after every single operation, now you can *chain* JSON navigation
calls like looking up an object field or array element, or casting to a string, so that you only
have to check the error code once at the very end.
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -521,7 +521,7 @@ static void twitter_image_sizes(State& state) {
set<tuple<uint64_t, uint64_t>> image_sizes; set<tuple<uint64_t, uint64_t>> image_sizes;
for (dom::object tweet : doc["statuses"]) { for (dom::object tweet : doc["statuses"]) {
dom::array media; dom::array media;
if (not (error = tweet["entities"]["media"].get(media))) { if (! (error = tweet["entities"]["media"].get(media))) {
for (dom::object image : media) { for (dom::object image : media) {
for (auto size : image["sizes"].get_object()) { for (auto size : image["sizes"].get_object()) {
image_sizes.emplace(size.value["w"], size.value["h"]); image_sizes.emplace(size.value["w"], size.value["h"]);
@@ -564,7 +564,7 @@ static void error_code_twitter_default_profile(State& state) noexcept {
for (dom::element tweet : tweets) { for (dom::element tweet : tweets) {
dom::object user; dom::object user;
if ((error = tweet["user"].get(user))) { return; } if ((error = tweet["user"].get(user))) { return; }
bool default_profile; bool default_profile{};
if ((error = user["default_profile"].get(default_profile))) { return; } if ((error = user["default_profile"].get(default_profile))) { return; }
if (default_profile) { if (default_profile) {
std::string_view screen_name; std::string_view screen_name;
@@ -638,7 +638,7 @@ static void error_code_twitter_image_sizes(State& state) noexcept {
if ((error = doc["statuses"].get(statuses))) { return; } if ((error = doc["statuses"].get(statuses))) { return; }
for (dom::element tweet : statuses) { for (dom::element tweet : statuses) {
dom::array images; dom::array images;
if (not (error = tweet["entities"]["media"].get(images))) { if (! (error = tweet["entities"]["media"].get(images))) {
for (dom::element image : images) { for (dom::element image : images) {
dom::object sizes; dom::object sizes;
if ((error = image["sizes"].get(sizes))) { return; } if ((error = image["sizes"].get(sizes))) { return; }
+14 -10
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,24 +503,28 @@ 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;
double freqall = (all_stages_without_allocation.best.cycles() / all_stages_without_allocation.best.elapsed_sec()) / 1000000000.0; double freqall = (all_stages_without_allocation.best.cycles() / all_stages_without_allocation.best.elapsed_sec()) / 1000000000.0;
double freqmin = min(freq1, freq2); double freqmin = min(freq1, freq2);
double freqmax = max(freq1, freq2); double freqmax = max(freq1, freq2);
if((freqall < 0.95 * freqmin) or (freqall > 1.05 * freqmax)) { if((freqall < 0.95 * freqmin) || (freqall > 1.05 * freqmax)) {
printf("\nWarning: The processor frequency fluctuates in an expected way!!!\n" printf("\nWarning: The processor frequency fluctuates in an expected way!!!\n"
"Range for stage 1 and stage 2 : [%.3f GHz, %.3f GHz], overall: %.3f GHz.\n", "Range for stage 1 and stage 2 : [%.3f GHz, %.3f GHz], overall: %.3f GHz.\n",
freqmin, freqmax, freqall); freqmin, freqmax, freqall);
+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];
} }
+29 -4
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(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,
@@ -145,12 +149,21 @@ struct event_collector {
PERF_COUNT_HW_CACHE_REFERENCES, PERF_COUNT_HW_CACHE_REFERENCES,
PERF_COUNT_HW_CACHE_MISSES PERF_COUNT_HW_CACHE_MISSES
#endif #endif
}, quiet) {} }) {}
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;
+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);
+3 -4
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);
@@ -100,9 +100,8 @@ simdjson2msgpack::to_msgpack(const simdjson::padded_string &json,
recursive_processor_ref(val); recursive_processor_ref(val);
#endif #endif
} }
if (doc.current_location().error() == simdjson::SUCCESS) { if (!doc.at_end()) {
// Example of error detection - this won't be reached on twitter.json in the benchmark. throw "There are unexpectedly tokens after the end of the json in the json2msgpack sample data";
throw "There are unexpectedly tokens after the end of the json in the json2msgpack sample data";
} }
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf)); return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
} }
@@ -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!)
+19 -34
View File
@@ -1,22 +1,13 @@
// https://github.com/WojciechMula/toys/blob/master/000helpers/linux-perf-events.h
#pragma once #pragma once
#ifdef __linux__ #ifdef __linux__
#ifdef __has_include
#if __has_include(<asm/unistd.h>)
#include <asm/unistd.h> // for __NR_perf_event_open #include <asm/unistd.h> // for __NR_perf_event_open
#else
#warning "Header asm/unistd.h cannot be found though it is a linux system. Are linux headers missing?"
#endif
#else // no __has_include
// Please insure that linux headers have been installed.
#include <asm/unistd.h> // for __NR_perf_event_open
#endif
#include <linux/perf_event.h> // for perf event constants #include <linux/perf_event.h> // for perf event constants
#include <sys/ioctl.h> // for ioctl #include <sys/ioctl.h> // for ioctl
#include <unistd.h> // for syscall #include <unistd.h> // for syscall
#include <cerrno> // for errno #include <cerrno> // for errno
#include <cstring> // for std::memset #include <cstring> // for memset
#include <stdexcept> #include <stdexcept>
#include <iostream> #include <iostream>
@@ -28,13 +19,11 @@ template <int TYPE = PERF_TYPE_HARDWARE> class LinuxEvents {
perf_event_attr attribs{}; perf_event_attr attribs{};
size_t num_events{}; size_t num_events{};
std::vector<uint64_t> temp_result_vec{}; std::vector<uint64_t> temp_result_vec{};
std::vector<uint64_t> result{}; std::vector<uint64_t> ids{};
std::vector<int> fds{};
bool quiet;
public: public:
explicit LinuxEvents(std::vector<int> config_vec, bool _quiet=false) : fd(0), working(true), quiet{_quiet} { explicit LinuxEvents(std::vector<int> config_vec) : fd(0), working(true) {
std::memset(&attribs, 0, sizeof(attribs)); memset(&attribs, 0, sizeof(attribs));
attribs.type = TYPE; attribs.type = TYPE;
attribs.size = sizeof(attribs); attribs.size = sizeof(attribs);
attribs.disabled = 1; attribs.disabled = 1;
@@ -49,7 +38,7 @@ public:
int group = -1; // no group int group = -1; // no group
num_events = config_vec.size(); num_events = config_vec.size();
result.resize(config_vec.size()); ids.resize(config_vec.size());
uint32_t i = 0; uint32_t i = 0;
for (auto config : config_vec) { for (auto config : config_vec) {
attribs.config = config; attribs.config = config;
@@ -57,22 +46,17 @@ public:
if (_fd == -1) { if (_fd == -1) {
report_error("perf_event_open"); report_error("perf_event_open");
} }
fd = _fd; // fd tracks the last _fd value. ioctl(_fd, PERF_EVENT_IOC_ID, &ids[i++]);
fds.push_back(fd);
ioctl(fd, PERF_EVENT_IOC_ID, &result[i++]);
if (group == -1) { if (group == -1) {
group = fd; group = _fd;
fd = _fd;
} }
} }
temp_result_vec.resize(num_events * 2 + 1); temp_result_vec.resize(num_events * 2 + 1);
} }
~LinuxEvents() { ~LinuxEvents() { if (fd != -1) { close(fd); } }
for (auto tfd : fds) {
if (tfd != -1) { close(tfd); }
}
}
inline void start() { inline void start() {
if (fd != -1) { if (fd != -1) {
@@ -97,10 +81,16 @@ public:
} }
} }
// our actual results are in slots 1,3,5, ... of this structure // our actual results are in slots 1,3,5, ... of this structure
// we really should be checking our result obtained earlier to be safe
for (uint32_t i = 1; i < temp_result_vec.size(); i += 2) { for (uint32_t i = 1; i < temp_result_vec.size(); i += 2) {
results[i / 2] = temp_result_vec[i]; results[i / 2] = temp_result_vec[i];
} }
for (uint32_t i = 2; i < temp_result_vec.size(); i += 2) {
if(ids[i/2-1] != temp_result_vec[i]) {
report_error("event mismatch");
}
}
} }
bool is_working() { bool is_working() {
@@ -108,13 +98,8 @@ public:
} }
private: private:
void report_error(const std::string &context) { void report_error(const std::string &) {
if (!quiet) {
if (working) {
std::cerr << (context + ": " + std::string(strerror(errno))) << std::endl;
}
}
working = false; working = false;
} }
}; };
#endif #endif
+43 -2
View File
@@ -50,6 +50,23 @@ undefined behavior.")
endif() endif()
endif() endif()
option(SIMDJSON_SANITIZE_MEMORY "Sanitize memory" OFF)
if(SIMDJSON_SANITIZE_MEMORY)
message(STATUS "Setting the memory sanitizer.")
add_compile_options(
-fsanitize=memory -fno-sanitize-recover=all
)
link_libraries(
-fsanitize=memory -fno-sanitize-recover=all
)
# Ubuntu bug for GCC 5.0+ (safe for all versions)
if(CMAKE_COMPILER_IS_GNUCC)
link_libraries(-fuse-ld=gold)
endif()
endif()
if(SIMDJSON_SANITIZE_THREADS) if(SIMDJSON_SANITIZE_THREADS)
message(STATUS "Setting both the thread sanitizer \ message(STATUS "Setting both the thread sanitizer \
and the undefined-behavior sanitizer.") and the undefined-behavior sanitizer.")
@@ -73,6 +90,8 @@ if(NOT is_multi_config AND NOT CMAKE_BUILD_TYPE)
if(SIMDJSON_SANITIZE OR SIMDJSON_SANITIZE_UNDEFINED) if(SIMDJSON_SANITIZE OR SIMDJSON_SANITIZE_UNDEFINED)
message(STATUS "No build type selected and you have enabled the sanitizer, \ message(STATUS "No build type selected and you have enabled the sanitizer, \
default to Debug. Consider setting CMAKE_BUILD_TYPE.") default to Debug. Consider setting CMAKE_BUILD_TYPE.")
message(STATUS "Setting debug optimization flag to -O1 to help sanitizer.")
set(CMAKE_CXX_FLAGS_DEBUG "-O1" CACHE STRING "" FORCE)
set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE)
else() else()
message(STATUS "No build type selected, default to Release") message(STATUS "No build type selected, default to Release")
@@ -91,13 +110,18 @@ endif()
# We compile tools, tests, etc. with C++ 17. Override yourself if you need on a # We compile tools, tests, etc. with C++ 17. Override yourself if you need on a
# target. # target.
set(CMAKE_CXX_STANDARD 17) 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_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)
@@ -144,6 +168,11 @@ else()
) )
endif() endif()
option(SIMDJSON_GLIBCXX_ASSERTIONS "Set _GLIBCXX_ASSERTIONS" OFF)
if (SIMDJSON_GLIBCXX_ASSERTIONS)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_GLIBCXX_ASSERTIONS")
endif()
# #
# Other optional flags # Other optional flags
# #
@@ -187,6 +216,18 @@ else()
message(STATUS "AVX-512 instructions are not allowed.") message(STATUS "AVX-512 instructions are not allowed.")
endif() endif()
option(
SIMDJSON_SKIPUTF8VALIDATION
"SKIP UTF8 VALIDATION."
OFF
)
if(SIMDJSON_SKIPUTF8VALIDATION)
add_compile_definitions(SIMDJSON_UTF8VALIDATION=0)
message(STATUS "SKIP UTF8 VALIDATION")
else()
add_compile_definitions(SIMDJSON_UTF8VALIDATION=1)
endif()
include(CheckSymbolExists) include(CheckSymbolExists)
check_symbol_exists(fork unistd.h HAVE_POSIX_FORK) check_symbol_exists(fork unistd.h HAVE_POSIX_FORK)
check_symbol_exists(wait sys/wait.h HAVE_POSIX_WAIT) check_symbol_exists(wait sys/wait.h HAVE_POSIX_WAIT)
+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)
+9 -1
View File
@@ -15,7 +15,7 @@ if(SIMDJSON_GOOGLE_BENCHMARKS)
set_off(BENCHMARK_ENABLE_INSTALL) set_off(BENCHMARK_ENABLE_INSTALL)
set_off(BENCHMARK_ENABLE_WERROR) set_off(BENCHMARK_ENABLE_WERROR)
import_dependency(google_benchmarks google/benchmark d572f47) import_dependency(google_benchmarks google/benchmark v1.7.1)
add_dependency(google_benchmarks) add_dependency(google_benchmarks)
endif() endif()
@@ -94,6 +94,14 @@ int main() {}
import_dependency(rapidjson Tencent/rapidjson f54b0e4) import_dependency(rapidjson Tencent/rapidjson f54b0e4)
add_library(rapidjson INTERFACE) add_library(rapidjson INTERFACE)
target_compile_definitions(rapidjson INTERFACE RAPIDJSON_HAS_STDSTRING) target_compile_definitions(rapidjson INTERFACE RAPIDJSON_HAS_STDSTRING)
include (TestBigEndian)
TEST_BIG_ENDIAN(IS_BIG_ENDIAN)
if(IS_BIG_ENDIAN)
target_compile_definitions(rapidjson INTERFACE RAPIDJSON_ENDIAN=1)
else()
target_compile_definitions(rapidjson INTERFACE RAPIDJSON_ENDIAN=0)
endif()
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) target_compile_definitions(rapidjson INTERFACE SIMDJSON_COMPETITION_RAPIDJSON)
+1 -1
View File
@@ -40,7 +40,7 @@ macro(add_dependency NAME)
message(FATAL_ERROR "Missing ${NAME}_SOURCE_DIR variable") message(FATAL_ERROR "Missing ${NAME}_SOURCE_DIR variable")
endif() endif()
add_subdirectory("${${NAME}_SOURCE_DIR}" "${PROJECT_BINARY_DIR}/_deps/${NAME}") add_subdirectory("${${NAME}_SOURCE_DIR}" "${PROJECT_BINARY_DIR}/_deps/${NAME}" EXCLUDE_FROM_ALL)
endmacro() endmacro()
function(set_off NAME) function(set_off NAME)
+564 -89
View File
@@ -12,7 +12,7 @@ An overview of what you need to know to use simdjson, with examples.
- [The Basics: Loading and Parsing JSON Documents](#the-basics-loading-and-parsing-json-documents) - [The Basics: Loading and Parsing JSON Documents](#the-basics-loading-and-parsing-json-documents)
- [Documents are Iterators](#documents-are-iterators) - [Documents are Iterators](#documents-are-iterators)
- [Parser, Document and JSON Scope](#parser-document-and-json-scope) - [Parser, Document and JSON Scope](#parser-document-and-json-scope)
- [C++11 Support and string_view](#c11-support-and-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)
- [Minifying JSON strings without parsing](#minifying-json-strings-without-parsing) - [Minifying JSON strings without parsing](#minifying-json-strings-without-parsing)
@@ -23,27 +23,30 @@ An overview of what you need to know to use simdjson, with examples.
- [Disabling Exceptions](#disabling-exceptions) - [Disabling Exceptions](#disabling-exceptions)
- [Exceptions](#exceptions) - [Exceptions](#exceptions)
- [Current location in document](#current-location-in-document) - [Current location in document](#current-location-in-document)
- [Checking for trailing content](#checking-for-trailing-content)
- [Rewinding](#rewinding) - [Rewinding](#rewinding)
- [Direct Access to the Raw String](#direct-access-to-the-raw-string)
- [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](#raw-strings)
- [General Direct Access to the Raw JSON String](#general-direct-access-to-the-raw-json-string)
- [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)
- [Performance Tips](#performance-tips)
Requirements Requirements
------------------ ------------------
- A recent compiler (LLVM clang 6 or better, GNU GCC 7.4 or better, Xcode 11 or better) on a 64-bit (PPC, ARM or x64 Intel/AMD) POSIX systems such as macOS, freeBSD or Linux. We require that the compiler supports the C++11 standard or better. - A recent compiler (LLVM clang 6 or better, GNU GCC 7.4 or better, Xcode 11 or better) on a 64-bit (PPC, ARM or x64 Intel/AMD) POSIX systems such as macOS, freeBSD or Linux. We require that the compiler supports the C++11 standard or better.
- Visual Studio 2017 or better under 64-bit Windows. Users should target a 64-bit build (x64) instead of a 32-bit build (x86). We support the LLVM clang compiler under Visual Studio (clangcl) as well as as the regular Visual Studio compiler. We also support MinGW 64-bit under Windows. - Visual Studio 2017 or better under 64-bit Windows. Users should target a 64-bit build (x64 or ARM64) instead of a 32-bit build (x86). We support the LLVM clang compiler under Visual Studio (clangcl) as well as as the regular Visual Studio compiler. We also support MinGW 64-bit under Windows.
Support for AVX-512 require a processor with AVX512-VBMI2 support (Ice Lake or better) under a 64-bit system and a recent compiler (LLVM clang 6 or better, GCC 8 or better, Visual Studio 2019 or better). You need a correspondingly recent assembler such as gas (2.30+) or nasm (2.14+): recent compilers usually come with recent assemblers. If you mix a recent compiler with an incompatible/old assembler (e.g., when using a recent compiler with an old Linux distribution), you may get errors at build time because the compiler produces instructions that the assembler does not recognize: you should update your assembler to match your compiler (e.g., upgrade binutils to version 2.30 or better under Linux) or use an older compiler matching the capabilities of your assembler. Support for AVX-512 require a processor with AVX512-VBMI2 support (Ice Lake or better, AMD Zen 4 or better) under a 64-bit system and a recent compiler (LLVM clang 6 or better, GCC 8 or better, Visual Studio 2019 or better). You need a correspondingly recent assembler such as gas (2.30+) or nasm (2.14+): recent compilers usually come with recent assemblers. If you mix a recent compiler with an incompatible/old assembler (e.g., when using a recent compiler with an old Linux distribution), you may get errors at build time because the compiler produces instructions that the assembler does not recognize: you should update your assembler to match your compiler (e.g., upgrade binutils to version 2.30 or better under Linux) or use an older compiler matching the capabilities of your assembler.
Because big-endian systems are effectively limited commercially to IBM mainframes today, the simdjson library is only tested on little-endian systems. Users who require big-endian support are invited to contribute to the library. We test the library on a big-endian system (IBM s390x with Linux) .
Including simdjson Including simdjson
------------------ ------------------
@@ -142,6 +145,12 @@ As required by the standard, your JSON document should be in a Unicode (UTF-8) s
string, from the beginning to the end, needs to be valid: we do not attempt to tolerate bad string, from the beginning to the end, needs to be valid: we do not attempt to tolerate bad
inputs before or after a document. inputs before or after a document.
For efficiency reasons, simdjson requires a string with a few bytes (`simdjson::SIMDJSON_PADDING`)
at the end, these bytes may be read but their content does not affect the parsing. In practice,
it means that the JSON inputs should be stored in a memory region with `simdjson::SIMDJSON_PADDING`
extra bytes at the end. You do not have to set these bytes to specific values though you may
want to if you want to avoid runtime warnings with some sanitizers.
The simdjson library offers a tree-like [API](https://en.wikipedia.org/wiki/API), which you can The simdjson library offers a tree-like [API](https://en.wikipedia.org/wiki/API), which you can
access by creating a `ondemand::parser` and calling the `iterate()` method. The iterate method access by creating a `ondemand::parser` and calling the `iterate()` method. The iterate method
quickly indexes the input string and may detect some errors. The following example illustrates quickly indexes the input string and may detect some errors. The following example illustrates
@@ -153,8 +162,7 @@ auto json = padded_string::load("twitter.json"); // load JSON file 'twitter.json
ondemand::document doc = parser.iterate(json); // position a pointer at the beginning of the JSON data ondemand::document doc = parser.iterate(json); // position a pointer at the beginning of the JSON data
``` ```
You can also create a padded string---for efficiency reasons, simdjson requires a string You can also create a padded string---and call `iterate()`:
with a few bytes (`simdjson::SIMDJSON_PADDING`) at the end---and calling `iterate()`:
```c++ ```c++
ondemand::parser parser; ondemand::parser parser;
@@ -174,11 +182,33 @@ 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, as long as the `capacity()` of
the string exceeds the `size()` by at least `SIMDJSON_PADDING`. You can increase the `capacity()` with the `reserve()` function of your strings. the string exceeds the `size()` by at least `SIMDJSON_PADDING`. You can increase the `capacity()` with the `reserve()` function of your strings.
You can copy your data directly on a `simdjson::padded_string` as follows:
```c++
const char * data = "my data"; // 7 bytes
simdjson::padded_string my_padded_data(data, 7); // copies to a padded buffer
```
Or as follows...
```c++
std::string data = "my data";
simdjson::padded_string my_padded_data(data); // copies to a padded buffer
```
We recommend against creating many `std::string` or many `std::padding_string` instances in your application to store your JSON data. We recommend against creating many `std::string` or many `std::padding_string` instances in your application to store your JSON data.
Consider reusing the same buffers and limiting memory allocations. Consider reusing the same buffers and limiting memory allocations.
By default, the simdjson library throws exceptions (`simdjson_error`) on errors. We omit `try`-`catch` clauses from our illustrating examples: if you omit `try`-`catch` in your code, an uncaught exception will halt your program. It is also possible to use simdjson without generating exceptions, and you may even build the library without exception support at all. See [Error Handling](#error-handling) for details. By default, the simdjson library throws exceptions (`simdjson_error`) on errors. We omit `try`-`catch` clauses from our illustrating examples: if you omit `try`-`catch` in your code, an uncaught exception will halt your program. It is also possible to use simdjson without generating exceptions, and you may even build the library without exception support at all. See [Error Handling](#error-handling) for details.
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/98Kx9Kqjn)
* [simdjson examples with errors without exceptions](https://godbolt.org/z/PKG7GdbPo)
Documents are Iterators Documents are Iterators
----------------------- -----------------------
@@ -208,7 +238,9 @@ For best performance, a `parser` instance should be reused over several files: o
needlessly reallocate memory, an expensive process. It is also possible to avoid entirely memory needlessly reallocate memory, an expensive process. It is also possible to avoid entirely memory
allocations during parsing when using simdjson. [See our performance notes for details](performance.md). allocations during parsing when using simdjson. [See our performance notes for details](performance.md).
C++11 Support and string_view If you need to have several documents active at once, you should have several parser instances.
string_view
------------- -------------
The simdjson library builds on compilers supporting the [C++11 standard](https://en.wikipedia.org/wiki/C%2B%2B11). The simdjson library builds on compilers supporting the [C++11 standard](https://en.wikipedia.org/wiki/C%2B%2B11).
@@ -287,29 +319,44 @@ We invite you to keep the following rules in mind:
2. Because On Demand is really just an iterator, you must fully consume the current object or array before accessing a sibling object or array. 2. Because On Demand is really just an iterator, you must fully consume the current object or array before accessing a sibling object or array.
3. Values can only be consumed once, you should get the values and store them if you plan to need them multiple times. You are expected to access the keys of an object just once. You are expected to go through the values of an array just once. 3. Values can only be consumed once, you should get the values and store them if you plan to need them multiple times. You are expected to access the keys of an object just once. You are expected to go through the values of an array just once.
The simdjson library makes generous use of `std::string_view` instances. If you are unfamiliar
with `std::string_view` in C++, make sure to [read the section on std::string_view](#string_view).
They behave much like an immutable `std::string` but they require no memory allocation. You can
create a `std::string` instance from an `std::string_view` when you need it.
The following specific instructions indicate how to use the JSON when exceptions are enabled, but simdjson has full, idiomatic The following specific instructions indicate how to use the JSON when exceptions are enabled, but simdjson has full, idiomatic
support for users who avoid exceptions. See [the simdjson error handling documentation](basics.md#error-handling) for more. support for users who avoid exceptions. See [the simdjson error handling documentation](basics.md#error-handling) for more.
* **Validate What You Use:** When calling `iterate`, the document is quickly indexed. If it is * **Validate What You Use:** When calling `iterate`, the document is quickly indexed. If it is
not a valid Unicode (UTF-8) string or if there is an unclosed string, an error may be reported right away. not a valid Unicode (UTF-8) string or if there is an unclosed string, an error may be reported right away.
However, it is not fully validated. On Demand only fully validates the values you use and the However, it is not fully validated. On Demand only fully validates the values you use and the
structure leading to it. structure leading to it. It means that at every step as you traverse the document, you may encounter an error. You can handle errors either with exceptions or with error codes.
* **Extracting Values:** You can cast a JSON element to a native type: * **Extracting Values:** You can cast a JSON element to a native type:
`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. 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. The `get_string()` returns a valid UTF-8 string, after 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
unescaping characters as needed: unmatched surrogate pairs are treated as an error. When calling `get_uint64()` and `get_int64()`, if the number does not fit in a corresponding 64-bit integer type, it is also considered an error. 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.
The `get_string()` returns a valid UTF-8 string, after
unescaping characters as needed: unmatched surrogate pairs are treated as an error unless you
pass `true` (`get_string(true)`) as a parameter to get replacement characters where errors
occur. If you somehow need to access non-UTF-8 strings in a lossless manner
(e.g., if you strings contain unpaired surrogates), you may use the `get_wobbly_string()` function to get a string in the [WTF-8 format](https://simonsapin.github.io/wtf-8).
When calling `get_uint64()` and `get_int64()`, if the number does not fit in a corresponding
64-bit integer type, it is also considered an error. When parsing numbers or other scalar values, the library checks
that the value is followed by an expected character, thus you *may* get a number parsing error when accessing the digits
as an integer in the following strings: `{"number":12332a`, `{"number":12332\0`, `{"number":12332` (the digits appear at the end). We always abide by the [RFC 8259](https://www.tbray.org/ongoing/When/201x/2017/12/14/rfc8259.html) JSON specification so that, for example, numbers prefixed by the `+` sign are in error.
> IMPORTANT NOTE: values can only be parsed once. Since documents are *iterators*, once you have > IMPORTANT NOTE: values can only be parsed once. Since documents are *iterators*, once you have
> parsed a value (such as by casting to double), you cannot get at it again. It is an error to call > parsed a value (such as by casting to double), you cannot get at it again. It is an error to call
> `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. If you consume an 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 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"]`, 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"]`.
If you have retrieved `content["bids"].get_array()` and you later call If you have retrieved `content["bids"].get_array()` and you later call
@@ -323,9 +370,14 @@ 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;
> ondemand::parser parser; > ondemand::parser parser;
> auto doc = parser.iterate(json); > auto doc = parser.iterate(json);
> ondemand::object object = doc.get_object(); > ondemand::object object = doc.get_object();
@@ -333,7 +385,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()); }
> } > }
> ``` > ```
> >
@@ -366,8 +418,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.
@@ -397,7 +451,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"]));
> } > }
> } > }
@@ -406,7 +460,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 << "]";
@@ -432,7 +486,7 @@ support for users who avoid exceptions. See [the simdjson error handling documen
``` ```
This examples also show how we can string several operations and only check for the error once, a strategy we call *error chaining*. This examples also show how we can string several operations and only check for the error once, a strategy we call *error chaining*.
Though error chaining makes the code very compact, it also makes error reporting less precise: in this instance, you may get the Though error chaining makes the code very compact, it also makes error reporting less precise: in this instance, you may get the
same error whether the field "str", "123" or "abc" is missing. If you need to break down error handling per operation, avoid error chaining. same error whether the field "str", "123" or "abc" is missing. If you need to break down error handling per operation, avoid error chaining. Furthermore, you should be mindful that chaining that harm performance by encouraging redundancies: writing both `doc["str"]["123"]["abc"].get(value)` and `doc["str"]["123"]["zyw"].get(value)` in the same program may force multiple accesses to the same keys (`"str"` and `"123"`).
* **Counting elements in arrays:** Sometimes it is useful to scan an array to determine its length prior to parsing it. * **Counting elements in arrays:** Sometimes it is useful to scan an array to determine its length prior to parsing it.
For this purpose, `array` instances have a `count_elements` method. Users should be For this purpose, `array` instances have a `count_elements` method. Users should be
aware that the `count_elements` method can be costly since it requires scanning the aware that the `count_elements` method can be costly since it requires scanning the
@@ -549,7 +603,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;
@@ -616,6 +670,41 @@ for (ondemand::object car : parser.iterate(cars_json)) {
} }
``` ```
The previous example had an array of objects, but we can use essentially the same
approach with an object of objects.
```c++
ondemand::parser parser;
auto cars_json = R"( {
"identifier1":{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
"identifier2":{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
"identifier3":{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
} )"_padded;
// Iterating through an array of objects
ondemand::document doc = parser.iterate(cars_json);
for (ondemand::field key_car : doc.get_object()) {
// If I need a string_view and/or, I can use key_car.unescaped_key() instead, but
// key_car.key() will be more performant otherwise.
cout << "identifier : " << key_car.key() << std::endl;
// I can now access the subobject:
ondemand::object car = key_car.value();
// Accessing a field by name
cout << "Make/Model: " << std::string_view(car["make"]) << "/" << std::string_view(car["model"]) << endl;
// Casting a JSON element to an integer
uint64_t year = car["year"];
cout << "- This car is " << 2020 - year << "years old." << endl;
// Iterating through an array of floats
double total_tire_pressure = 0;
for (double tire_pressure : car["tire_pressure"]) {
total_tire_pressure += tire_pressure;
}
cout << "- Average tire pressure: " << (total_tire_pressure / 4) << endl;
}
```
The following example illustrates how you may also iterate through object values, effectively visiting all key-value pairs in the object. The following example illustrates how you may also iterate through object values, effectively visiting all key-value pairs in the object.
```C++ ```C++
@@ -804,10 +893,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.
@@ -820,11 +916,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;
} }
@@ -886,10 +982,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) {
@@ -920,12 +1016,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;
} }
``` ```
@@ -949,40 +1045,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;
@@ -998,7 +1094,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
@@ -1012,18 +1108,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(),
// 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;
} }
} }
@@ -1065,10 +1163,32 @@ int main(void) {
} }
``` ```
You can do handle errors gracefully as well...
```C++
#include <iostream>
#include "simdjson.h"
int main(void) {
simdjson::ondemand::parser parser;
simdjson::padded_string json_string;
simdjson::ondemand::document doc;
try {
json_string = padded_string::load("twitter.json");
doc = parser.iterate(json_string);
uint64_t identifier = doc["statuses"].at(0)["id"];
std::cout << identifier << std::endl;
} catch (simdjson::simdjson_error &error) {
std::cerr << "JSON error: " << error.what() << " near "
<< doc.current_location() << " in " << json_string << std::endl;
}
}
```
### Current location in document ### Current location in document
Sometimes, it might be helpful to know the current location in the document during iteration. This is especially useful when encountering errors. The `current_location()` method on a Sometimes, it might be helpful to know the current location in the document during iteration. This is especially useful when encountering errors. The `current_location()` method on a
`document` instances makes it easy to identify common JSON errors. Users can call the `current_location()` method on a validdocument instance to retrieve a `const char *` pointer to the current location in the document. This method also works even after an error has invalidated the document and the parser (e.g. `TAPE_ERROR`, `INCOMPLETE_ARRAY_OR_OBJECT`). `document` instances makes it easy to identify common JSON errors. Users can call the `current_location()` method on a valid document instance to retrieve a `const char *` pointer to the current location in the document. This method also works even after an error has invalidated the document and the parser (e.g. `TAPE_ERROR`, `INCOMPLETE_ARRAY_OR_OBJECT`).
When the input was a `padding_string` or another null-terminated source, then you may When the input was a `padding_string` or another null-terminated source, then you may
use the `const char *` pointer as a C string. As an example, consider the following use the `const char *` pointer as a C string. As an example, consider the following
example where we used the exception-free simdjson interface: example where we used the exception-free simdjson interface:
@@ -1081,6 +1201,12 @@ int64_t i;
auto error = doc["integer"].get_int64().get(i); // Expect to get integer from "integer" key, but get TAPE_ERROR auto error = doc["integer"].get_int64().get(i); // Expect to get integer from "integer" key, but get TAPE_ERROR
if (error) { if (error) {
std::cout << error << std::endl; // Prints TAPE_ERROR error message std::cout << error << std::endl; // Prints TAPE_ERROR error message
// Recover a pointer to the location of the first error:
const char * ptr;
doc.current_location().get(ptr);
// ptr points at 'false, "integer": -343} " which is the location of the error
//
// Because we pad simdjson::padded_string instances with null characters, you may also do the following:
std::cout<< doc.current_location() << std::endl; // Prints "false, "integer": -343} " (location of TAPE_ERROR) std::cout<< doc.current_location() << std::endl; // Prints "false, "integer": -343} " (location of TAPE_ERROR)
} }
``` ```
@@ -1157,6 +1283,32 @@ contains control characters that must be escaped and UNCLOSED_STRING if there
is an unclosed string in the document. We do not provide location information for these is an unclosed string in the document. We do not provide location information for these
errors. errors.
### Checking for trailing content
The parser validates all parsed content, but your code may exhaust the content while
not having processed the entire document. Thus, as a final optional step, you may
call `at_end()` on the document instance. If it returns `false`, then you may
conclude that you have trailing content and that your document is not valid JSON.
You may then use `doc.current_location()` to obtain a pointer to the start of the trailing
content.
```C++
auto json = R"([1, 2] foo ])"_padded;
ondemand::parser parser;
ondemand::document doc = parser.iterate(json);
ondemand::array array = doc.get_array();
for (uint64_t values : array) {
std::cout << values << std::endl;
}
if (!doc.at_end()) {
// 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;
}
```
The `at_end()` method is equivalent to `doc.current_location().error() == simdjson::SUCCESS` but
more convenient.
Rewinding Rewinding
---------- ----------
@@ -1178,7 +1330,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
@@ -1195,41 +1347,6 @@ internal string buffer. Thus you should consume values only once
even if you can iterate through the array or object more than once. even if you can iterate through the array or object more than once.
If you unescape a string within an array more than once, you have unsafe code. If you unescape a string within an array more than once, you have unsafe code.
Direct Access to the Raw String
--------------------------------
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
have different needs. For example, some users might want to support big integers.
The library makes this possible by providing a `raw_json_token` method which returns
a `std::string_view` instance containing the value as a string which you may then
parse as you see fit.
```C++
simdjson::ondemand::parser parser;
simdjson::padded_string docdata = R"({"value":12321323213213213213213213213211223})"_padded;
simdjson::ondemand::document doc = parser.iterate(docdata);
simdjson::ondemand::object obj = doc.get_object();
std::string_view token = obj["value"].raw_json_token();
// token has value 12321323213213213213213213213211223, it points inside the input string
```
The `raw_json_token` method even works when the JSON value is a string. In such cases, it
will return the complete string with the quotes and with eventual escaped sequences as in the
source document.
```C++
simdjson::ondemand::parser parser;
simdjson::padded_string docdata = R"({"value":"12321323213213213213213213213211223"})"_padded;
simdjson::ondemand::document doc = parser.iterate(docdata);
simdjson::ondemand::object obj = doc.get_object();
string_view token = obj["value"].raw_json_token();
// token has value "12321323213213213213213213213211223", it points inside the input string
```
The `raw_json_token()` should be fast and free of allocation.
Newline-Delimited JSON (ndjson) and JSON lines Newline-Delimited JSON (ndjson) and JSON lines
---------------------------------------------- ----------------------------------------------
@@ -1281,18 +1398,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;
@@ -1318,10 +1435,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
------------------------------ ------------------------------
@@ -1534,6 +1650,78 @@ JSON string to a user-provided buffer:
} }
``` ```
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
string. The simdjson library allows you to have access to the raw underlying JSON
more generally.
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
have different needs. For example, some users might want to support big integers.
The library makes this possible by providing a `raw_json_token` method which returns
a `std::string_view` instance containing the value as a string which you may then
parse as you see fit.
```C++
simdjson::ondemand::parser parser;
simdjson::padded_string docdata = R"({"value":12321323213213213213213213213211223})"_padded;
simdjson::ondemand::document doc = parser.iterate(docdata);
simdjson::ondemand::object obj = doc.get_object();
std::string_view token = obj["value"].raw_json_token();
// token has value 12321323213213213213213213213211223, it points inside the input string
```
The `raw_json_token` method even works when the JSON value is a string. In such cases, it
will return the complete string with the quotes and with eventual escaped sequences as in the
source document.
```C++
simdjson::ondemand::parser parser;
simdjson::padded_string docdata = R"({"value":"12321323213213213213213213213211223"})"_padded;
simdjson::ondemand::document doc = parser.iterate(docdata);
simdjson::ondemand::object obj = doc.get_object();
string_view token = obj["value"].raw_json_token();
// token has value "12321323213213213213213213213211223", it points inside the input string
```
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
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.
```C++
simdjson::ondemand::parser parser;
simdjson::padded_string docdata = R"({"value":123})"_padded;
simdjson::ondemand::document doc = parser.iterate(docdata);
simdjson::ondemand::object obj = doc.get_object();
string_view token = obj.raw_json(); // gives you `{"value":123}`
```
```C++
simdjson::ondemand::parser parser;
simdjson::padded_string docdata = R"([1,2,3])"_padded;
simdjson::ondemand::document doc = parser.iterate(docdata);
simdjson::ondemand::array arr = doc.get_array();
string_view token = arr.raw_json(); // gives you `[1,2,3]`
```
Because `raw_json()` consumes to object or the array, if you want to both have
access to the raw string, and also use the array or object, you should call `reset()`.
```C++
simdjson::ondemand::parser parser;
simdjson::padded_string docdata = R"({"value":123})"_padded;
simdjson::ondemand::document doc = parser.iterate(docdata);
simdjson::ondemand::object obj = doc.get_object();
string_view token = obj.raw_json(); // gives you `{"value":123}`
obj.reset(); // revise the object
uint64_t x = obj["value"]; // gives me 123
```
Thread Safety Thread Safety
------------- -------------
@@ -1574,3 +1762,290 @@ Backwards Compatibility
The only header file supported by simdjson is `simdjson.h`. Older versions of simdjson published a The only header file supported by simdjson is `simdjson.h`. Older versions of simdjson published a
number of other include files such as `document.h` or `ParsedJson.h` alongside `simdjson.h`; these headers number of other include files such as `document.h` or `ParsedJson.h` alongside `simdjson.h`; these headers
may be moved or removed in future versions. may be moved or removed in future versions.
Examples
--------
Some users like to have example. The following code samples illustrate how to process specific JSON inputs.
For simplicity, we do not include full error support: this code would throw exceptions on error.
* Example 1: ZuluBBox
```C++
struct ZuluBBox {
double xmin;
double ymin;
double width;
double height;
void print() {
std::cout << xmin << ", " << ymin << ", " << width << ", " << height
<< std::endl;
}
};
bool example() {
auto json = R"+( {
"ZuluROI": {
"ZuluBBox": {
"xmin": 0,
"ymin": 0,
"width": 1,
"height": 1
},
"SubObjects": [
{
"ZuluDetection": {
"label": "car",
"class_id": 3,
"confidence": 0.7587034106254578,
"ZuluBBox": {
"xmin": 0.3843536376953125,
"ymin": 0.4532909393310547,
"width": 0.09115534275770187,
"height": 0.04127710685133934
},
"SubObjects": []
}
},
{
"ZuluDetection": {
"label": "car",
"class_id": 3,
"confidence": 0.6718865633010864,
"ZuluBBox": {
"xmin": 0.7500002980232239,
"ymin": 0.5212296843528748,
"width": 0.07592231780290604,
"height": 0.038947589695453644
},
"SubObjects": []
}
},
{
"ZuluDetection": {
"label": "car",
"class_id": 3,
"confidence": 0.5806200504302979,
"ZuluBBox": {
"xmin": 0.9025363922119141,
"ymin": 0.5925348401069641,
"width": 0.05478987470269203,
"height": 0.046337299048900604
},
"SubObjects": []
}
}
]
},
"timestamp (ms)": 1677085594421,
"buffer_offset": 35673
} )+"_padded;
ondemand::parser parser;
ondemand::document doc = parser.iterate(json);
ondemand::object root_object = doc.get_object();
ondemand::object roi_object = root_object["ZuluROI"];
ondemand::object box_roi_object = roi_object["ZuluBBox"];
ZuluBBox box = {
double(box_roi_object["xmin"]), double(box_roi_object["ymin"]),
double(box_roi_object["width"]), double(box_roi_object["height"])};
box.print();
for (ondemand::object value : roi_object["SubObjects"]) {
ondemand::object detect = value["ZuluDetection"];
std::cout << detect["label"].get_string() << std::endl;
std::cout << detect["class_id"].get_uint64() << std::endl;
std::cout << detect["confidence"].get_double() << std::endl;
ondemand::object vbox_roi_object = detect["ZuluBBox"];
ZuluBBox vbox = {
double(vbox_roi_object["xmin"]), double(vbox_roi_object["ymin"]),
double(vbox_roi_object["width"]), double(vbox_roi_object["height"])};
vbox.print();
}
std::cout << root_object["timestamp (ms)"].get_uint64() << std::endl;
std::cout << root_object["buffer_offset"].get_uint64() << std::endl;
return true;
}
```
* Example 2: Demos
```C++
bool example() {
auto json = R"+( {
"5f08a730b280e54fd1e75a7046b93fdc": {
"file": "/DEMOS/0-9/10_Orbyte.sid",
"len": [
"1:17"
],
"loud": [
"-22.8"
],
"name": "10 Orbyte",
"author": "Michael Becker (Premium)",
"release": "2014 Tristar & Red Sector Inc.",
"bits": 20
},
"2727236ead44a62f0c6e01f6dd4dc484": {
"file": "/DEMOS/0-9/12345.sid",
"len": [
"0:56"
],
"loud": [
"-33.3"
],
"name": "12345",
"author": "Beal",
"release": "1988 Beal",
"bits": 20
},
"7ea765fce6c0f92570b18adc7bf52f54": {
"file": "/DEMOS/0-9/128_Byte_Blues_BASIC.sid",
"len": [
"0:18"
],
"loud": [
"-27.1"
],
"name": "128 Byte Blues",
"author": "Leonard J. Paul (Freaky DNA)",
"release": "2005 Freaky DNA",
"bits": 62
}
} )+"_padded;
ondemand::parser parser;
ondemand::document doc = parser.iterate(json);
ondemand::object root_object = doc.get_object();
for(auto key_value : root_object) {
// could get std::string_view with 'unescaped_key()':
std::cout << "key: " << key_value.key() << std::endl;
ondemand::object obj = key_value.value();
std::cout << "file: " << std::string_view(obj["file"]) << std::endl;
std::cout << "len: ";
for(std::string_view values : obj["len"]) {
std::cout << values << std::endl;
}
std::cout << std::endl;
std::cout << "loud: ";
for(std::string_view values : obj["loud"]) {
std::cout << values << std::endl;
}
std::cout << std::endl;
std::cout << "name: " << std::string_view(obj["name"]) << std::endl;
std::cout << "author: " << std::string_view(obj["author"]) << std::endl;
std::cout << "release: " << std::string_view(obj["release"]) << std::endl;
std::cout << "bits: " << uint64_t(obj["bits"]) << std::endl;
}
return true;
}
```
* 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;
}
```
Performance Tips
--------
- The On Demand front-end works best when doing a single pass over the input: avoid calling `count_elements`, `rewind` and similar methods.
- If you are familiar with assembly language, you may use the online tool godbolt to explore the compiled code. The following example may work: [https://godbolt.org/z/xE4GWs573](https://godbolt.org/z/xE4GWs573).
- 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 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...
```C++
std::string_view make = o["data"]["make"];
std::string_view model = o["data"]["model"];
std::string_view year = o["data"]["year"];
```
We expect that it is more efficient to access the `"data"` key once:
```C++
simdjson::ondemand::object data = o["data"];
std::string_view model = data["model"];
std::string_view year = data["year"];
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 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.
+24 -3
View File
@@ -16,6 +16,7 @@ An overview of what you need to know to use simdjson, with examples.
* [Server Loops: Long-Running Processes and Memory Capacity](#server-loops-long-running-processes-and-memory-capacity) * [Server Loops: Long-Running Processes and Memory Capacity](#server-loops-long-running-processes-and-memory-capacity)
* [Best Use of the DOM API](#best-use-of-the-dom-api) * [Best Use of the DOM API](#best-use-of-the-dom-api)
* [Padding and Temporary Copies](#padding-and-temporary-copies) * [Padding and Temporary Copies](#padding-and-temporary-copies)
* [Performance Tips](#performance-tips)
DOM vs On Demand DOM vs On Demand
---------------------------------------------- ----------------------------------------------
@@ -44,6 +45,20 @@ dom::parser parser;
dom::element doc = parser.parse("[1,2,3]"_padded); // parse a string, the _padded suffix creates a simdjson::padded_string instance dom::element doc = parser.parse("[1,2,3]"_padded); // parse a string, the _padded suffix creates a simdjson::padded_string instance
``` ```
You can copy your data directly on a `simdjson::padded_string` as follows:
```c++
const char * data = "my data"; // 7 bytes
simdjson::padded_string my_padded_data(data, 7); // copies to a padded buffer
```
Or as follows...
```c++
std::string data = "my data";
simdjson::padded_string my_padded_data(data); // copies to a padded buffer
```
The parsed document resulting from the `parser.load` and `parser.parse` calls depends on the `parser` instance. Thus the `parser` instance must remain in scope. Furthermore, you must have at most one parsed document in play per `parser` instance. The parsed document resulting from the `parser.load` and `parser.parse` calls depends on the `parser` instance. Thus the `parser` instance must remain in scope. Furthermore, you must have at most one parsed document in play per `parser` instance.
You cannot copy a `parser` instance, you may only move it. You cannot copy a `parser` instance, you may only move it.
@@ -90,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
@@ -314,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;
} }
@@ -644,3 +659,9 @@ simdjson::dom::element element = parser.parse(padded_json_copy.get(), json_len,
```` ````
Setting the `realloc_if_needed` parameter `false` in this manner may lead to better performance since copies are avoided, but it requires that the user takes more responsibilities: the simdjson library cannot verify that the input buffer was padded with SIMDJSON_PADDING extra bytes. Setting the `realloc_if_needed` parameter `false` in this manner may lead to better performance since copies are avoided, but it requires that the user takes more responsibilities: the simdjson library cannot verify that the input buffer was padded with SIMDJSON_PADDING extra bytes.
Performance Tips
---------------------
- 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` directrive, 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.
+7 -6
View File
@@ -21,12 +21,13 @@ The current implementations are:
* haswell: AVX2 (2013 Intel Haswell or later) * haswell: AVX2 (2013 Intel Haswell or later)
* 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. Users are advised that the library is not tested on big-endian systems. * 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.
* 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 3 implementations compiles *all* the implementations into the executable. On Intel, it will include 4 implementations
(haswell, westmere and fallback), on ARM it will include 2 (arm64 and fallback), and on PPC it will include 2 (ppc64 and fallback). (icelake, haswell, westmere and fallback), on ARM it will include 2 (arm64 and fallback), and on PPC
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
these implementations at compile time with `-DSIMDJSON_IMPLEMENTATION_X=0` (where X is ICELAKE, HASWELL, these implementations at compile time with `-DSIMDJSON_IMPLEMENTATION_X=0` (where X is ICELAKE, HASWELL,
@@ -100,8 +101,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;
``` ```
@@ -112,7 +113,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;
} }
} }
+54 -3
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;
} }
@@ -237,3 +252,39 @@ 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
-----------
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
```
+5 -5
View File
@@ -679,11 +679,11 @@ 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:
@@ -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; }
} }
``` ```
@@ -752,7 +752,7 @@ On relevant systems, the On Demand API provides some support for runtime dispatc
Some users wish to run at the best possible speed. Under recent Intel and AMD processors, these users should take additional steps to verify that their code is well optimized. Some users wish to run at the best possible speed. Under recent Intel and AMD processors, these users should take additional steps to verify that their code is well optimized.
Given that the On Demand API offer limited runtime dispatching, it matters that your code is compiled against a specific CPU target. You should verify that the code is compiled against the target you expect. Thankfully, the simdjson library will tell you exactly what it detects as an implementation: `haswell` (AVX2 x64 processors), `westmere` (SSE4 x64 processors), `arm64` (64-bit ARM), `ppc64` (64-bit POWER), `fallback` (others). Under x64 processors, many programmers will want to target `haswell` whereas under ARM, most programmers will want to target `arm64` (and it should do so automatically). The `fallback` is probably only good for testing purposes, not for deployment. Given that the On Demand API offer limited runtime dispatching, it matters that your code is compiled against a specific CPU target. You should verify that the code is compiled against the target you expect. Thankfully, the simdjson library will tell you exactly what it detects as an implementation: `icelake` (AVX512 x64 processors), `haswell` (AVX2 x64 processors), `westmere` (SSE4 x64 processors), `arm64` (64-bit ARM), `ppc64` (64-bit POWER), `fallback` (others). Under x64 processors, many programmers will want to target `haswell` whereas under ARM, most programmers will want to target `arm64` (and it should do so automatically). The `fallback` is probably only good for testing purposes, not for deployment.
```C++ ```C++
std::cout << simdjson::builtin_implementation()->name() << std::endl; std::cout << simdjson::builtin_implementation()->name() << std::endl;
+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;
} }
+18 -4
View File
@@ -3,7 +3,10 @@ Performance Notes
simdjson strives to be at its fastest *without tuning*, and generally achieves this. However, there simdjson strives to be at its fastest *without tuning*, and generally achieves this. However, there
are still some scenarios where tuning can enhance performance. are still some scenarios where tuning can enhance performance.
Once your code is tested, we
further encourage you to define `NDEBUG` in your Release builds to disable additional runtime
testing and get the best performance.
* [NDEBUG directive](#ndebug-directive)
* [Reusing the parser for maximum efficiency](#reusing-the-parser-for-maximum-efficiency) * [Reusing the parser for maximum efficiency](#reusing-the-parser-for-maximum-efficiency)
* [Reusing string buffers](#reusing-string-buffers) * [Reusing string buffers](#reusing-string-buffers)
* [Server Loops: Long-Running Processes and Memory Capacity](#server-loops-long-running-processes-and-memory-capacity) * [Server Loops: Long-Running Processes and Memory Capacity](#server-loops-long-running-processes-and-memory-capacity)
@@ -12,6 +15,18 @@ are still some scenarios where tuning can enhance performance.
* [Visual Studio](#visual-studio) * [Visual Studio](#visual-studio)
* [Power Usage and Downclocking](#power-usage-and-downclocking) * [Power Usage and Downclocking](#power-usage-and-downclocking)
NDEBUG directive
-------------
In C/C++, the `NDEBUG` pre-processor directive is not set by default. When it is not set, the simdjson library does
many additional checks that may impact negatively the performance. We recommend that, once your code
is well tested, you define `NDEBUG` directive in your Release builds. The `NDEBUG` directive should be defined
prior to including the `simdjson.h` header.
The `NDEBUG` directive is generally independent from optimization flags. For example, setting `-O3` under
GCC does not set the `NDEBUG` directive.
Reusing the parser for maximum efficiency Reusing the parser for maximum efficiency
----------------------------------------- -----------------------------------------
@@ -138,7 +153,7 @@ few hundred megabytes per second if your JSON documents are densely packed with
Visual Studio Visual Studio
-------------- --------------
On Intel and AMD Windows platforms, Microsoft Visual Studio enables programmers to build either 32-bit (x86) or 64-bit (x64) binaries. We urge you to always use 64-bit mode. Visual Studio 2019 should default on 64-bit builds when you have a 64-bit version of Windows, which we recommend. On Intel and AMD Windows platforms, Microsoft Visual Studio enables programmers to build either 32-bit (x86) or 64-bit (x64 or ARM64) binaries. We urge you to always use 64-bit mode. Visual Studio 2019 should default on 64-bit builds when you have a 64-bit version of Windows, which we recommend.
When compiling with Visual Studio, we recommend the flags `/Ob2 /O2` or better. We do not recommend that you compile simdjson with architecture-specific flags such as `arch:AVX2`. The simdjson library automatically selects the best execution kernel at runtime. When compiling with Visual Studio, we recommend the flags `/Ob2 /O2` or better. We do not recommend that you compile simdjson with architecture-specific flags such as `arch:AVX2`. The simdjson library automatically selects the best execution kernel at runtime.
@@ -160,8 +175,7 @@ You should not expect the simdjson library to cause *downclocking* of your recen
- [Whenever 512-bit AVX-512 instructions are used](https://lemire.me/blog/2018/09/07/avx-512-when-and-how-to-use-these-new-instructions/). - [Whenever 512-bit AVX-512 instructions are used](https://lemire.me/blog/2018/09/07/avx-512-when-and-how-to-use-these-new-instructions/).
- Whenever heavy 256-bit or wider instructions are used. Heavy instructions are those involving floating point operations or integer multiplications (since these execute on the floating point unit). - Whenever heavy 256-bit or wider instructions are used. Heavy instructions are those involving floating point operations or integer multiplications (since these execute on the floating point unit).
The simdjson library does not make use of heavy 256-bit instructions. We do use vectorized multiplications, but only using 128-bit registers. Thus there should be no downclocking due to simdjson on recent processors, except when AVX-512 is allowed and The simdjson library does not generally make use of heavy 256-bit instructions. On AVX2 kernels, we use vectorized multiplications, but only using 128-bit registers. On recent processors (Ice Lake/Tiger Lake or better, AMD Zen 4 or better) [no frequency throttling is found](https://travisdowns.github.io/blog/2020/08/19/icl-avx512-freq.html) due to SIMD instructions: we are thus more aggressive with SIMD on these machines. If you can still concerned, you can easily disable AVX-512 with the CMake option `SIMDJSON_AVX512_ALLOWED` set to `OFF` (e.g., `cmake -D SIMDJSON_AVX512_ALLOWED=OFF -B build && cmake --build build`) or by setting
detected. However, we only allow AVX-512 on recent processors (Ice Lake/Tiger Lake or better) where [little to no frequency throttling is expected](https://travisdowns.github.io/blog/2020/08/19/icl-avx512-freq.html). If you can still concerned, you can easily disable AVX-512 with the CMake option `SIMDJSON_AVX512_ALLOWED` set to `OFF` (e.g., `cmake -D SIMDJSON_AVX512_ALLOWED=OFF -B build && cmake --build build`) or by setting
the macro `SIMDJSON_AVX512_ALLOWED` to `0` in C++ prior to importing the headers. the macro `SIMDJSON_AVX512_ALLOWED` to `0` in C++ prior to importing the headers.
You may still be worried about which SIMD instruction set is used by simdjson. Thankfully, [you can always determine and change which architecture-specific implementation is used](implementation-selection.md) by simdjson. Thus even if your CPU supports AVX2, you do not need to use AVX2. You are in control. You may still be worried about which SIMD instruction set is used by simdjson. Thankfully, [you can always determine and change which architecture-specific implementation is used](implementation-selection.md) by simdjson. Thus even if your CPU supports AVX2, you do not need to use AVX2. You are in control.
+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
+11 -2
View File
@@ -1,14 +1,23 @@
#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,
// but the algorithms do not end up using the returned value. // but the algorithms do not end up using the returned value.
// Sadly, sanitizers are not smart enough to figure it out. // Sadly, sanitizers are not smart enough to figure it out.
SIMDJSON_NO_SANITIZE_UNDEFINED SIMDJSON_NO_SANITIZE_UNDEFINED
// This function can be used safely even if not all bytes have been
// initialized.
// See issue https://github.com/simdjson/simdjson/issues/1965
SIMDJSON_NO_SANITIZE_MEMORY
simdjson_inline int trailing_zeroes(uint64_t input_num) { simdjson_inline int trailing_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO #ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
unsigned long ret; unsigned long ret;
@@ -91,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
+7 -6
View File
@@ -1,17 +1,18 @@
#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; * @private
using namespace simdjson::dom; */
}
class implementation final : public simdjson::implementation { class implementation final : public simdjson::implementation {
public: public:
simdjson_inline implementation() : simdjson::implementation("arm64", "ARM NEON", internal::instruction_set::NEON) {} simdjson_inline implementation() : simdjson::implementation("arm64", "ARM NEON", internal::instruction_set::NEON) {}
+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
+6 -6
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 {
@@ -527,7 +527,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
+35 -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,11 +309,35 @@ 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
#define SIMDJSON_DEVELOPMENT_ASSERT(expr) do { } while (0) #define SIMDJSON_DEVELOPMENT_ASSERT(expr) do { } while (0)
#endif #endif
#ifndef SIMDJSON_UTF8VALIDATION
#define SIMDJSON_UTF8VALIDATION 1
#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 -7
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"
@@ -30,6 +26,4 @@ SIMDJSON_DISABLE_UNDESIRED_WARNINGS
#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
+1 -10
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.
*/ */
+54
View File
@@ -0,0 +1,54 @@
#ifndef SIMDJSON_DOM_BASE_H
#define SIMDJSON_DOM_BASE_H
#include "simdjson/base.h"
namespace simdjson {
/**
* @brief A DOM API on top of the simdjson parser.
*/
namespace dom {
/** The default batch size for parser.parse_many() and parser.load_many() */
static constexpr size_t DEFAULT_BATCH_SIZE = 1000000;
/**
* Some adversary might try to set the batch size to 0 or 1, which might cause problems.
* We set a minimum of 32B since anything else is highly likely to be an error. In practice,
* most users will want a much larger batch size.
*
* All non-negative MINIMAL_BATCH_SIZE values should be 'safe' except that, obviously, no JSON
* document can ever span 0 or 1 byte and that very large values would create memory allocation issues.
*/
static constexpr size_t MINIMAL_BATCH_SIZE = 32;
/**
* It is wasteful to allocate memory for tiny documents (e.g., 4 bytes).
*/
static constexpr size_t MINIMAL_DOCUMENT_CAPACITY = 32;
class array;
class document;
class document_stream;
class element;
class key_value_pair;
class object;
class parser;
#ifdef SIMDJSON_THREADS_ENABLED
struct stage1_worker;
#endif // SIMDJSON_THREADS_ENABLED
} // namespace dom
namespace internal {
template<typename T>
class string_builder;
class tape_ref;
} // namespace internal
} // namespace simdjson
#endif // SIMDJSON_DOM_BASE_H
+7 -6
View File
@@ -1,13 +1,14 @@
#ifndef SIMDJSON_INLINE_DOCUMENT_H #ifndef SIMDJSON_DOCUMENT_INL_H
#define SIMDJSON_INLINE_DOCUMENT_H #define SIMDJSON_DOCUMENT_INL_H
// Inline implementations go in here. // Inline implementations go in here.
#include "simdjson/dom/base.h"
#include "simdjson/dom/document.h" #include "simdjson/dom/document.h"
#include "simdjson/dom/element.h" #include "simdjson/dom/element-inl.h"
#include "simdjson/internal/tape_ref.h" #include "simdjson/internal/tape_ref-inl.h"
#include "simdjson/internal/jsonformatutils.h" #include "simdjson/internal/jsonformatutils.h"
#include <ostream>
#include <cstring> #include <cstring>
namespace simdjson { namespace simdjson {
@@ -155,4 +156,4 @@ inline bool document::dump_raw_tape(std::ostream &os) const noexcept {
} // namespace dom } // namespace dom
} // namespace simdjson } // namespace simdjson
#endif // SIMDJSON_INLINE_DOCUMENT_H #endif // SIMDJSON_DOCUMENT_INL_H
+2 -4
View File
@@ -1,15 +1,13 @@
#ifndef SIMDJSON_DOM_DOCUMENT_H #ifndef SIMDJSON_DOM_DOCUMENT_H
#define SIMDJSON_DOM_DOCUMENT_H #define SIMDJSON_DOM_DOCUMENT_H
#include "simdjson/common_defs.h" #include "simdjson/dom/base.h"
#include <memory> #include <memory>
#include <ostream>
namespace simdjson { namespace simdjson {
namespace dom { namespace dom {
class element;
/** /**
* A parsed JSON document. * A parsed JSON document.
* *
+10 -6
View File
@@ -1,14 +1,18 @@
#ifndef SIMDJSON_INLINE_DOCUMENT_STREAM_H #ifndef SIMDJSON_DOCUMENT_STREAM_INL_H
#define SIMDJSON_INLINE_DOCUMENT_STREAM_H #define SIMDJSON_DOCUMENT_STREAM_INL_H
#include "simdjson/dom/base.h"
#include "simdjson/dom/document_stream.h" #include "simdjson/dom/document_stream.h"
#include <algorithm> #include "simdjson/dom/element-inl.h"
#include <limits> #include "simdjson/dom/parser-inl.h"
#include <stdexcept> #include "simdjson/error-inl.h"
#include "simdjson/internal/dom_parser_implementation.h"
namespace simdjson { namespace simdjson {
namespace dom { namespace dom {
#ifdef SIMDJSON_THREADS_ENABLED #ifdef SIMDJSON_THREADS_ENABLED
inline void stage1_worker::finish() { inline void stage1_worker::finish() {
// After calling "run" someone would call finish() to wait // After calling "run" someone would call finish() to wait
// for the end of the processing. // for the end of the processing.
@@ -337,4 +341,4 @@ simdjson_inline dom::document_stream::iterator simdjson_result<dom::document_str
#endif // SIMDJSON_EXCEPTIONS #endif // SIMDJSON_EXCEPTIONS
} // namespace simdjson } // namespace simdjson
#endif // SIMDJSON_INLINE_DOCUMENT_STREAM_H #endif // SIMDJSON_DOCUMENT_STREAM_INL_H
+2 -3
View File
@@ -1,9 +1,9 @@
#ifndef SIMDJSON_DOCUMENT_STREAM_H #ifndef SIMDJSON_DOCUMENT_STREAM_H
#define SIMDJSON_DOCUMENT_STREAM_H #define SIMDJSON_DOCUMENT_STREAM_H
#include "simdjson/common_defs.h" #include "simdjson/dom/base.h"
#include "simdjson/dom/parser.h" #include "simdjson/dom/parser.h"
#include "simdjson/error.h"
#ifdef SIMDJSON_THREADS_ENABLED #ifdef SIMDJSON_THREADS_ENABLED
#include <thread> #include <thread>
#include <mutex> #include <mutex>
@@ -13,7 +13,6 @@
namespace simdjson { namespace simdjson {
namespace dom { namespace dom {
#ifdef SIMDJSON_THREADS_ENABLED #ifdef SIMDJSON_THREADS_ENABLED
/** @private Custom worker class **/ /** @private Custom worker class **/
struct stage1_worker { struct stage1_worker {
+12 -6
View File
@@ -1,11 +1,17 @@
#ifndef SIMDJSON_INLINE_ELEMENT_H #ifndef SIMDJSON_ELEMENT_INL_H
#define SIMDJSON_INLINE_ELEMENT_H #define SIMDJSON_ELEMENT_INL_H
#include "simdjson/dom/array.h" #include "simdjson/dom/base.h"
#include "simdjson/dom/element.h" #include "simdjson/dom/element.h"
#include "simdjson/dom/document.h"
#include "simdjson/dom/object.h" #include "simdjson/dom/object.h"
#include <cstring> #include "simdjson/internal/tape_type.h"
#include <utility>
#include "simdjson/dom/object-inl.h"
#include "simdjson/error-inl.h"
#include <ostream>
#include <limits>
namespace simdjson { namespace simdjson {
@@ -438,4 +444,4 @@ inline std::ostream& operator<<(std::ostream& out, element_type type) {
} // namespace simdjson } // namespace simdjson
#endif // SIMDJSON_INLINE_ELEMENT_H #endif // SIMDJSON_ELEMENT_INL_H
+2 -12
View File
@@ -1,20 +1,11 @@
#ifndef SIMDJSON_DOM_ELEMENT_H #ifndef SIMDJSON_DOM_ELEMENT_H
#define SIMDJSON_DOM_ELEMENT_H #define SIMDJSON_DOM_ELEMENT_H
#include "simdjson/common_defs.h" #include "simdjson/dom/base.h"
#include "simdjson/error.h" #include "simdjson/dom/array.h"
#include "simdjson/internal/tape_ref.h"
#include <ostream>
namespace simdjson { namespace simdjson {
namespace internal {
template<typename T>
class string_builder;
}
namespace dom { namespace dom {
class array;
class document;
class object;
/** /**
* The actual concrete type of a JSON element * The actual concrete type of a JSON element
@@ -537,7 +528,6 @@ public:
#endif // SIMDJSON_EXCEPTIONS #endif // SIMDJSON_EXCEPTIONS
}; };
} // namespace simdjson } // namespace simdjson
#endif // SIMDJSON_DOM_DOCUMENT_H #endif // SIMDJSON_DOM_DOCUMENT_H
+5 -3
View File
@@ -3,9 +3,11 @@
#ifndef SIMDJSON_DOM_JSONPARSER_H #ifndef SIMDJSON_DOM_JSONPARSER_H
#define SIMDJSON_DOM_JSONPARSER_H #define SIMDJSON_DOM_JSONPARSER_H
#include "simdjson/dom/document.h" #include "simdjson/dom/base.h"
#include "simdjson/dom/parsedjson.h" #include "simdjson/dom/parser.h"
#include "simdjson/jsonioutil.h" #include "simdjson/dom/element.h"
#include "simdjson/dom/parser-inl.h"
namespace simdjson { namespace simdjson {
+9 -6
View File
@@ -1,11 +1,14 @@
#ifndef SIMDJSON_INLINE_OBJECT_H #ifndef SIMDJSON_OBJECT_INL_H
#define SIMDJSON_INLINE_OBJECT_H #define SIMDJSON_OBJECT_INL_H
#include "simdjson/dom/element.h" #include "simdjson/dom/base.h"
#include "simdjson/dom/object.h" #include "simdjson/dom/object.h"
#include "simdjson/portability.h" #include "simdjson/dom/document.h"
#include "simdjson/dom/element-inl.h"
#include "simdjson/error-inl.h"
#include <cstring> #include <cstring>
#include <string>
namespace simdjson { namespace simdjson {
@@ -253,4 +256,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_OBJECT_H #endif // SIMDJSON_OBJECT_INL_H
+2 -10
View File
@@ -1,21 +1,13 @@
#ifndef SIMDJSON_DOM_OBJECT_H #ifndef SIMDJSON_DOM_OBJECT_H
#define SIMDJSON_DOM_OBJECT_H #define SIMDJSON_DOM_OBJECT_H
#include "simdjson/common_defs.h" #include "simdjson/dom/base.h"
#include "simdjson/error.h" #include "simdjson/dom/element.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;
class key_value_pair;
/** /**
* JSON object. * JSON object.
*/ */
+1 -1
View File
@@ -3,7 +3,7 @@
#ifndef SIMDJSON_DOM_PARSEDJSON_H #ifndef SIMDJSON_DOM_PARSEDJSON_H
#define SIMDJSON_DOM_PARSEDJSON_H #define SIMDJSON_DOM_PARSEDJSON_H
#include "simdjson/dom/document.h" #include "simdjson/dom/base.h"
namespace simdjson { namespace simdjson {
+60 -4
View File
@@ -1,9 +1,17 @@
#ifndef SIMDJSON_INLINE_PARSEDJSON_ITERATOR_H #ifndef SIMDJSON_PARSEDJSON_ITERATOR_INL_H
#define SIMDJSON_INLINE_PARSEDJSON_ITERATOR_H #define SIMDJSON_PARSEDJSON_ITERATOR_INL_H
#include "simdjson/dom/base.h"
#include "simdjson/dom/parsedjson_iterator.h" #include "simdjson/dom/parsedjson_iterator.h"
#include "simdjson/portability.h" #include "simdjson/internal/jsonformatutils.h"
#include "simdjson/dom/parser-inl.h"
#include "simdjson/internal/tape_ref-inl.h"
#include <cstring> #include <cstring>
#include <iterator>
#include <limits>
#include <ostream>
#ifndef SIMDJSON_DISABLE_DEPRECATED_API #ifndef SIMDJSON_DISABLE_DEPRECATED_API
@@ -197,6 +205,12 @@ void dom::parser::Iterator::to_start_scope() {
current_type = uint8_t(current_val >> 56); current_type = uint8_t(current_val >> 56);
} }
inline void dom::parser::Iterator::rewind() {
while (up())
;
}
bool dom::parser::Iterator::next() { bool dom::parser::Iterator::next() {
size_t npos; size_t npos;
if ((current_type == '[') || (current_type == '{')) { if ((current_type == '[') || (current_type == '{')) {
@@ -365,6 +379,48 @@ bool dom::parser::Iterator::move_to(const char *pointer,
return found; return found;
} }
inline bool dom::parser::Iterator::move_to(const std::string &pointer) {
return move_to(pointer.c_str(), uint32_t(pointer.length()));
}
inline int64_t dom::parser::Iterator::get_integer() const {
if (location + 1 >= tape_length) {
return 0; // default value in case of error
}
return static_cast<int64_t>(doc.tape[location + 1]);
}
inline uint64_t dom::parser::Iterator::get_unsigned_integer() const {
if (location + 1 >= tape_length) {
return 0; // default value in case of error
}
return doc.tape[location + 1];
}
inline const char * dom::parser::Iterator::get_string() const {
return reinterpret_cast<const char *>(
doc.string_buf.get() + (current_val & internal::JSON_VALUE_MASK) + sizeof(uint32_t));
}
inline uint32_t dom::parser::Iterator::get_string_length() const {
uint32_t answer;
std::memcpy(&answer,
reinterpret_cast<const char *>(doc.string_buf.get() +
(current_val & internal::JSON_VALUE_MASK)),
sizeof(uint32_t));
return answer;
}
inline double dom::parser::Iterator::get_double() const {
if (location + 1 >= tape_length) {
return std::numeric_limits<double>::quiet_NaN(); // default value in
// case of error
}
double answer;
std::memcpy(&answer, &doc.tape[location + 1], sizeof(answer));
return answer;
}
bool dom::parser::Iterator::relative_move_to(const char *pointer, bool dom::parser::Iterator::relative_move_to(const char *pointer,
uint32_t length) { uint32_t length) {
if (length == 0) { if (length == 0) {
@@ -486,4 +542,4 @@ SIMDJSON_POP_DISABLE_WARNINGS
#endif // SIMDJSON_DISABLE_DEPRECATED_API #endif // SIMDJSON_DISABLE_DEPRECATED_API
#endif // SIMDJSON_INLINE_PARSEDJSON_ITERATOR_H #endif // SIMDJSON_PARSEDJSON_ITERATOR_INL_H
+9 -50
View File
@@ -3,16 +3,8 @@
#ifndef SIMDJSON_DOM_PARSEDJSON_ITERATOR_H #ifndef SIMDJSON_DOM_PARSEDJSON_ITERATOR_H
#define SIMDJSON_DOM_PARSEDJSON_ITERATOR_H #define SIMDJSON_DOM_PARSEDJSON_ITERATOR_H
#include <cstring> #include "simdjson/dom/base.h"
#include <string> #include "simdjson/dom/parser.h"
#include <ostream>
#include <iterator>
#include <limits>
#include <stdexcept>
#include "simdjson/dom/document.h"
#include "simdjson/dom/parsedjson.h"
#include "simdjson/internal/jsonformatutils.h"
#ifndef SIMDJSON_DISABLE_DEPRECATED_API #ifndef SIMDJSON_DISABLE_DEPRECATED_API
@@ -52,51 +44,23 @@ public:
} }
// get the int64_t value at this node; valid only if get_type is "l" // get the int64_t value at this node; valid only if get_type is "l"
inline int64_t get_integer() const { inline int64_t get_integer() const;
if (location + 1 >= tape_length) {
return 0; // default value in case of error
}
return static_cast<int64_t>(doc.tape[location + 1]);
}
// get the value as uint64; valid only if if get_type is "u" // get the value as uint64; valid only if if get_type is "u"
inline uint64_t get_unsigned_integer() const { inline uint64_t get_unsigned_integer() const;
if (location + 1 >= tape_length) {
return 0; // default value in case of error
}
return doc.tape[location + 1];
}
// get the string value at this node (NULL ended); valid only if get_type is " // get the string value at this node (NULL ended); valid only if get_type is "
// note that tabs, and line endings are escaped in the returned value (see // note that tabs, and line endings are escaped in the returned value (see
// print_with_escapes) return value is valid UTF-8, it may contain NULL chars // print_with_escapes) return value is valid UTF-8, it may contain NULL chars
// within the string: get_string_length determines the true string length. // within the string: get_string_length determines the true string length.
inline const char *get_string() const { inline const char *get_string() const;
return reinterpret_cast<const char *>(
doc.string_buf.get() + (current_val & internal::JSON_VALUE_MASK) + sizeof(uint32_t));
}
// return the length of the string in bytes // return the length of the string in bytes
inline uint32_t get_string_length() const { inline uint32_t get_string_length() const;
uint32_t answer;
std::memcpy(&answer,
reinterpret_cast<const char *>(doc.string_buf.get() +
(current_val & internal::JSON_VALUE_MASK)),
sizeof(uint32_t));
return answer;
}
// get the double value at this node; valid only if // get the double value at this node; valid only if
// get_type() is "d" // get_type() is "d"
inline double get_double() const { inline double get_double() const;
if (location + 1 >= tape_length) {
return std::numeric_limits<double>::quiet_NaN(); // default value in
// case of error
}
double answer;
std::memcpy(&answer, &doc.tape[location + 1], sizeof(answer));
return answer;
}
inline bool is_object_or_array() const { return is_object() || is_array(); } inline bool is_object_or_array() const { return is_object() || is_array(); }
@@ -190,9 +154,7 @@ public:
// "If a referenced member name is not unique in an object, the member that // "If a referenced member name is not unique in an object, the member that
// is referenced is undefined, and evaluation fails". Here we just return // is referenced is undefined, and evaluation fails". Here we just return
// the first corresponding value. // the first corresponding value.
inline bool move_to(const std::string &pointer) { inline bool move_to(const std::string &pointer);
return move_to(pointer.c_str(), uint32_t(pointer.length()));
}
private: private:
// Almost the same as move_to(), except it searches from the current // Almost the same as move_to(), except it searches from the current
@@ -240,10 +202,7 @@ public:
// a scope is a series of nodes at the same level // a scope is a series of nodes at the same level
inline void to_start_scope(); inline void to_start_scope();
inline void rewind() { inline void rewind();
while (up())
;
}
+12 -8
View File
@@ -1,12 +1,16 @@
#ifndef SIMDJSON_INLINE_PARSER_H #ifndef SIMDJSON_PARSER_INL_H
#define SIMDJSON_INLINE_PARSER_H #define SIMDJSON_PARSER_INL_H
#include "simdjson/dom/base.h"
#include "simdjson/dom/document_stream.h" #include "simdjson/dom/document_stream.h"
#include "simdjson/dom/parser.h"
#include "simdjson/implementation.h" #include "simdjson/implementation.h"
#include "simdjson/internal/jsonformatutils.h" #include "simdjson/internal/dom_parser_implementation.h"
#include "simdjson/portability.h"
#include <cstdio> #include "simdjson/error-inl.h"
#include "simdjson/padded_string-inl.h"
#include "simdjson/dom/document_stream-inl.h"
#include "simdjson/dom/element-inl.h"
#include <climits> #include <climits>
namespace simdjson { namespace simdjson {
@@ -226,7 +230,7 @@ inline error_code parser::ensure_capacity(document& target_document, size_t desi
} }
simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept { simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
if(max_capacity < MINIMAL_DOCUMENT_CAPACITY) { if(max_capacity > MINIMAL_DOCUMENT_CAPACITY) {
_max_capacity = max_capacity; _max_capacity = max_capacity;
} else { } else {
_max_capacity = MINIMAL_DOCUMENT_CAPACITY; _max_capacity = MINIMAL_DOCUMENT_CAPACITY;
@@ -236,4 +240,4 @@ simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
} // namespace dom } // namespace dom
} // namespace simdjson } // namespace simdjson
#endif // SIMDJSON_INLINE_PARSER_H #endif // SIMDJSON_PARSER_INL_H
+7 -31
View File
@@ -1,41 +1,13 @@
#ifndef SIMDJSON_DOM_PARSER_H #ifndef SIMDJSON_DOM_PARSER_H
#define SIMDJSON_DOM_PARSER_H #define SIMDJSON_DOM_PARSER_H
#include "simdjson/common_defs.h" #include "simdjson/dom/base.h"
#include "simdjson/dom/document.h" #include "simdjson/dom/document.h"
#include "simdjson/error.h"
#include "simdjson/internal/dom_parser_implementation.h"
#include "simdjson/internal/tape_ref.h"
#include "simdjson/padded_string.h"
#include "simdjson/portability.h"
#include <memory>
#include <ostream>
#include <string>
namespace simdjson { namespace simdjson {
namespace dom { namespace dom {
class document_stream;
class element;
/** The default batch size for parser.parse_many() and parser.load_many() */
static constexpr size_t DEFAULT_BATCH_SIZE = 1000000;
/**
* Some adversary might try to set the batch size to 0 or 1, which might cause problems.
* We set a minimum of 32B since anything else is highly likely to be an error. In practice,
* most users will want a much larger batch size.
*
* All non-negative MINIMAL_BATCH_SIZE values should be 'safe' except that, obviously, no JSON
* document can ever span 0 or 1 byte and that very large values would create memory allocation issues.
*/
static constexpr size_t MINIMAL_BATCH_SIZE = 32;
/**
* It is wasteful to allocate memory for tiny documents (e.g., 4 bytes).
*/
static constexpr size_t MINIMAL_DOCUMENT_CAPACITY = 32;
/** /**
* A persistent document parser. * A persistent document parser.
* *
@@ -145,7 +117,9 @@ public:
* ### REQUIRED: Buffer Padding * ### REQUIRED: Buffer Padding
* *
* The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
* those bytes are initialized to, as long as they are allocated. * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
* using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
* SIMDJSON_PADDING bytes to avoid runtime warnings.
* *
* If realloc_if_needed is true (the default), it is assumed that the buffer does *not* have enough padding, * If realloc_if_needed is true (the default), it is assumed that the buffer does *not* have enough padding,
* and it is copied into an enlarged temporary buffer before parsing. Thus the following is safe: * and it is copied into an enlarged temporary buffer before parsing. Thus the following is safe:
@@ -408,7 +382,9 @@ public:
* ### REQUIRED: Buffer Padding * ### REQUIRED: Buffer Padding
* *
* The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what * The buffer must have at least SIMDJSON_PADDING extra allocated bytes. It does not matter what
* those bytes are initialized to, as long as they are allocated. * those bytes are initialized to, as long as they are allocated. These bytes will be read: if you
* using a sanitizer that verifies that no uninitialized byte is read, then you should initialize the
* SIMDJSON_PADDING bytes to avoid runtime warnings.
* *
* ### Threads * ### Threads
* *
+131 -23
View File
@@ -2,10 +2,16 @@
#ifndef SIMDJSON_SERIALIZATION_INL_H #ifndef SIMDJSON_SERIALIZATION_INL_H
#define SIMDJSON_SERIALIZATION_INL_H #define SIMDJSON_SERIALIZATION_INL_H
#include "simdjson/dom/base.h"
#include "simdjson/dom/serialization.h" #include "simdjson/dom/serialization.h"
#include "simdjson/dom/parser.h"
#include "simdjson/internal/tape_type.h"
#include <cinttypes> #include "simdjson/dom/array-inl.h"
#include <type_traits> #include "simdjson/dom/object-inl.h"
#include "simdjson/internal/tape_ref-inl.h"
#include <cstring>
namespace simdjson { namespace simdjson {
namespace dom { namespace dom {
@@ -17,12 +23,46 @@ inline bool parser::print_json(std::ostream &os) const noexcept {
os << answer; os << answer;
return true; return true;
} }
inline std::ostream& operator<<(std::ostream& out, simdjson::dom::element value) {
simdjson::internal::string_builder<> sb;
sb.append(value);
return (out << sb.str());
} }
#if SIMDJSON_EXCEPTIONS
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::dom::element> x) {
if (x.error()) { throw simdjson::simdjson_error(x.error()); }
return (out << x.value());
}
#endif
inline std::ostream& operator<<(std::ostream& out, simdjson::dom::array value) {
simdjson::internal::string_builder<> sb;
sb.append(value);
return (out << sb.str());
}
#if SIMDJSON_EXCEPTIONS
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::dom::array> x) {
if (x.error()) { throw simdjson::simdjson_error(x.error()); }
return (out << x.value());
}
#endif
inline std::ostream& operator<<(std::ostream& out, simdjson::dom::object value) {
simdjson::internal::string_builder<> sb;
sb.append(value);
return (out << sb.str());
}
#if SIMDJSON_EXCEPTIONS
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::dom::object> x) {
if (x.error()) { throw simdjson::simdjson_error(x.error()); }
return (out << x.value());
}
#endif
} // namespace dom
/*** /***
* Number utility functions * Number utility functions
**/ **/
namespace { namespace {
/**@private /**@private
* Escape sequence like \b or \u0001 * Escape sequence like \b or \u0001
@@ -41,7 +81,7 @@ struct escape_sequence {
* adds the to_chars functions which would do as well, but * adds the to_chars functions which would do as well, but
* we want to support C++11. * we want to support C++11.
*/ */
char *fast_itoa(char *output, int64_t value) noexcept { static char *fast_itoa(char *output, int64_t value) noexcept {
// This is a standard implementation of itoa. // This is a standard implementation of itoa.
char buffer[20]; char buffer[20];
uint64_t value_positive; uint64_t value_positive;
@@ -83,7 +123,7 @@ char *fast_itoa(char *output, int64_t value) noexcept {
* adds the to_chars functions which would do as well, but * adds the to_chars functions which would do as well, but
* we want to support C++11. * we want to support C++11.
*/ */
char *fast_itoa(char *output, uint64_t value) noexcept { static char *fast_itoa(char *output, uint64_t value) noexcept {
// This is a standard implementation of itoa. // This is a standard implementation of itoa.
char buffer[20]; char buffer[20];
const char *const end_buffer = buffer + 20; const char *const end_buffer = buffer + 20;
@@ -100,6 +140,8 @@ char *fast_itoa(char *output, uint64_t value) noexcept {
std::memcpy(output, write_pointer, len); std::memcpy(output, write_pointer, len);
return output + len; return output + len;
} }
} // anonymous namespace } // anonymous namespace
namespace internal { namespace internal {
@@ -107,19 +149,22 @@ namespace internal {
* Minifier/formatter code. * Minifier/formatter code.
**/ **/
simdjson_inline void mini_formatter::number(uint64_t x) { template<class formatter>
simdjson_inline void base_formatter<formatter>::number(uint64_t x) {
char number_buffer[24]; char number_buffer[24];
char *newp = fast_itoa(number_buffer, x); char *newp = fast_itoa(number_buffer, x);
buffer.insert(buffer.end(), number_buffer, newp); buffer.insert(buffer.end(), number_buffer, newp);
} }
simdjson_inline void mini_formatter::number(int64_t x) { template<class formatter>
simdjson_inline void base_formatter<formatter>::number(int64_t x) {
char number_buffer[24]; char number_buffer[24];
char *newp = fast_itoa(number_buffer, x); char *newp = fast_itoa(number_buffer, x);
buffer.insert(buffer.end(), number_buffer, newp); buffer.insert(buffer.end(), number_buffer, newp);
} }
simdjson_inline void mini_formatter::number(double x) { template<class formatter>
simdjson_inline void base_formatter<formatter>::number(double x) {
char number_buffer[24]; char number_buffer[24];
// Currently, passing the nullptr to the second argument is // Currently, passing the nullptr to the second argument is
// safe because our implementation does not check the second // safe because our implementation does not check the second
@@ -128,31 +173,51 @@ simdjson_inline void mini_formatter::number(double x) {
buffer.insert(buffer.end(), number_buffer, newp); buffer.insert(buffer.end(), number_buffer, newp);
} }
simdjson_inline void mini_formatter::start_array() { one_char('['); } template<class formatter>
simdjson_inline void mini_formatter::end_array() { one_char(']'); } simdjson_inline void base_formatter<formatter>::start_array() { one_char('['); }
simdjson_inline void mini_formatter::start_object() { one_char('{'); }
simdjson_inline void mini_formatter::end_object() { one_char('}'); }
simdjson_inline void mini_formatter::comma() { one_char(','); }
simdjson_inline void mini_formatter::true_atom() { template<class formatter>
simdjson_inline void base_formatter<formatter>::end_array() { one_char(']'); }
template<class formatter>
simdjson_inline void base_formatter<formatter>::start_object() { one_char('{'); }
template<class formatter>
simdjson_inline void base_formatter<formatter>::end_object() { one_char('}'); }
template<class formatter>
simdjson_inline void base_formatter<formatter>::comma() { one_char(','); }
template<class formatter>
simdjson_inline void base_formatter<formatter>::true_atom() {
const char * s = "true"; const char * s = "true";
buffer.insert(buffer.end(), s, s + 4); buffer.insert(buffer.end(), s, s + 4);
} }
simdjson_inline void mini_formatter::false_atom() {
template<class formatter>
simdjson_inline void base_formatter<formatter>::false_atom() {
const char * s = "false"; const char * s = "false";
buffer.insert(buffer.end(), s, s + 5); buffer.insert(buffer.end(), s, s + 5);
} }
simdjson_inline void mini_formatter::null_atom() {
template<class formatter>
simdjson_inline void base_formatter<formatter>::null_atom() {
const char * s = "null"; const char * s = "null";
buffer.insert(buffer.end(), s, s + 4); buffer.insert(buffer.end(), s, s + 4);
} }
simdjson_inline void mini_formatter::one_char(char c) { buffer.push_back(c); }
simdjson_inline void mini_formatter::key(std::string_view unescaped) { template<class formatter>
simdjson_inline void base_formatter<formatter>::one_char(char c) { buffer.push_back(c); }
template<class formatter>
simdjson_inline void base_formatter<formatter>::key(std::string_view unescaped) {
string(unescaped); string(unescaped);
one_char(':'); one_char(':');
} }
simdjson_inline void mini_formatter::string(std::string_view unescaped) {
template<class formatter>
simdjson_inline void base_formatter<formatter>::string(std::string_view unescaped) {
one_char('\"'); one_char('\"');
size_t i = 0; size_t i = 0;
// Fast path for the case where we have no control character, no ", and no backslash. // Fast path for the case where we have no control character, no ", and no backslash.
@@ -231,14 +296,46 @@ simdjson_inline void mini_formatter::string(std::string_view unescaped) {
one_char('\"'); one_char('\"');
} }
inline void mini_formatter::clear() {
template<class formatter>
inline void base_formatter<formatter>::clear() {
buffer.clear(); buffer.clear();
} }
simdjson_inline std::string_view mini_formatter::str() const { template<class formatter>
simdjson_inline std::string_view base_formatter<formatter>::str() const {
return std::string_view(buffer.data(), buffer.size()); return std::string_view(buffer.data(), buffer.size());
} }
simdjson_inline void mini_formatter::print_newline() {
return;
}
simdjson_inline void mini_formatter::print_indents(size_t depth) {
(void)depth;
return;
}
simdjson_inline void mini_formatter::print_space() {
return;
}
simdjson_inline void pretty_formatter::print_newline() {
one_char('\n');
}
simdjson_inline void pretty_formatter::print_indents(size_t depth) {
if(this->indent_step <= 0) {
return;
}
for(size_t i = 0; i < this->indent_step * depth; i++) {
one_char(' ');
}
}
simdjson_inline void pretty_formatter::print_space() {
one_char(' ');
}
/*** /***
* String building code. * String building code.
@@ -258,11 +355,16 @@ inline void string_builder<serializer>::append(simdjson::dom::element value) {
// print commas after each value // print commas after each value
if (after_value) { if (after_value) {
format.comma(); format.comma();
format.print_newline();
} }
format.print_indents(depth);
// If we are in an object, print the next key and :, and skip to the next // If we are in an object, print the next key and :, and skip to the next
// value. // value.
if (is_object[depth]) { if (is_object[depth]) {
format.key(iter.get_string_view()); format.key(iter.get_string_view());
format.print_space();
iter.json_index++; iter.json_index++;
} }
switch (iter.tape_ref_type()) { switch (iter.tape_ref_type()) {
@@ -291,6 +393,7 @@ inline void string_builder<serializer>::append(simdjson::dom::element value) {
is_object[depth] = false; is_object[depth] = false;
after_value = false; after_value = false;
format.print_newline();
continue; continue;
} }
@@ -318,6 +421,7 @@ inline void string_builder<serializer>::append(simdjson::dom::element value) {
is_object[depth] = true; is_object[depth] = true;
after_value = false; after_value = false;
format.print_newline();
continue; continue;
} }
@@ -362,17 +466,21 @@ inline void string_builder<serializer>::append(simdjson::dom::element value) {
// Handle multiple ends in a row // Handle multiple ends in a row
while (depth != 0 && (iter.tape_ref_type() == tape_type::END_ARRAY || while (depth != 0 && (iter.tape_ref_type() == tape_type::END_ARRAY ||
iter.tape_ref_type() == tape_type::END_OBJECT)) { iter.tape_ref_type() == tape_type::END_OBJECT)) {
format.print_newline();
depth--;
format.print_indents(depth);
if (iter.tape_ref_type() == tape_type::END_ARRAY) { if (iter.tape_ref_type() == tape_type::END_ARRAY) {
format.end_array(); format.end_array();
} else { } else {
format.end_object(); format.end_object();
} }
depth--;
iter.json_index++; iter.json_index++;
} }
// Stop when we're at depth 0 // Stop when we're at depth 0
} while (depth != 0); } while (depth != 0);
format.print_newline();
} }
template <class serializer> template <class serializer>
+126 -85
View File
@@ -1,13 +1,10 @@
#ifndef SIMDJSON_SERIALIZATION_H #ifndef SIMDJSON_SERIALIZATION_H
#define SIMDJSON_SERIALIZATION_H #define SIMDJSON_SERIALIZATION_H
#include "simdjson/common_defs.h" #include "simdjson/dom/base.h"
#include "simdjson/dom/document.h" #include "simdjson/dom/element.h"
#include "simdjson/error.h" #include "simdjson/dom/object.h"
#include "simdjson/internal/dom_parser_implementation.h"
#include "simdjson/internal/tape_ref.h"
#include "simdjson/padded_string.h"
#include "simdjson/portability.h"
#include <vector> #include <vector>
namespace simdjson { namespace simdjson {
@@ -19,7 +16,90 @@ namespace simdjson {
*/ */
namespace internal { namespace internal {
class mini_formatter; template<class formatter>
class base_formatter {
public:
/** Add a comma **/
simdjson_inline void comma();
/** Start an array, prints [ **/
simdjson_inline void start_array();
/** End an array, prints ] **/
simdjson_inline void end_array();
/** Start an array, prints { **/
simdjson_inline void start_object();
/** Start an array, prints } **/
simdjson_inline void end_object();
/** Prints a true **/
simdjson_inline void true_atom();
/** Prints a false **/
simdjson_inline void false_atom();
/** Prints a null **/
simdjson_inline void null_atom();
/** Prints a number **/
simdjson_inline void number(int64_t x);
/** Prints a number **/
simdjson_inline void number(uint64_t x);
/** Prints a number **/
simdjson_inline void number(double x);
/** Prints a key (string + colon) **/
simdjson_inline void key(std::string_view unescaped);
/** Prints a string. The string is escaped as needed. **/
simdjson_inline void string(std::string_view unescaped);
/** Clears out the content. **/
simdjson_inline void clear();
/**
* Get access to the buffer, it is owned by the instance, but
* the user can make a copy.
**/
simdjson_inline std::string_view str() const;
/** Prints one character **/
simdjson_inline void one_char(char c);
simdjson_inline void call_print_newline() {
this->print_newline();
}
simdjson_inline void call_print_indents(size_t depth) {
this->print_indents(depth);
}
simdjson_inline void call_print_space() {
this->print_space();
}
protected:
// implementation details (subject to change)
/** Backing buffer **/
std::vector<char> buffer{}; // not ideal!
};
/**
* @private This is the class that we expect to use with the string_builder
* template. It tries to produce a compact version of the JSON element
* as quickly as possible.
*/
class mini_formatter : public base_formatter<mini_formatter> {
public:
simdjson_inline void print_newline();
simdjson_inline void print_indents(size_t depth);
simdjson_inline void print_space();
};
class pretty_formatter : public base_formatter<pretty_formatter> {
public:
simdjson_inline void print_newline();
simdjson_inline void print_indents(size_t depth);
simdjson_inline void print_space();
protected:
int indent_step = 4;
};
/** /**
* @private The string_builder template allows us to construct * @private The string_builder template allows us to construct
@@ -55,56 +135,6 @@ private:
formatter format{}; formatter format{};
}; };
/**
* @private This is the class that we expect to use with the string_builder
* template. It tries to produce a compact version of the JSON element
* as quickly as possible.
*/
class mini_formatter {
public:
mini_formatter() = default;
/** Add a comma **/
simdjson_inline void comma();
/** Start an array, prints [ **/
simdjson_inline void start_array();
/** End an array, prints ] **/
simdjson_inline void end_array();
/** Start an array, prints { **/
simdjson_inline void start_object();
/** Start an array, prints } **/
simdjson_inline void end_object();
/** Prints a true **/
simdjson_inline void true_atom();
/** Prints a false **/
simdjson_inline void false_atom();
/** Prints a null **/
simdjson_inline void null_atom();
/** Prints a number **/
simdjson_inline void number(int64_t x);
/** Prints a number **/
simdjson_inline void number(uint64_t x);
/** Prints a number **/
simdjson_inline void number(double x);
/** Prints a key (string + colon) **/
simdjson_inline void key(std::string_view unescaped);
/** Prints a string. The string is escaped as needed. **/
simdjson_inline void string(std::string_view unescaped);
/** Clears out the content. **/
simdjson_inline void clear();
/**
* Get access to the buffer, it is owned by the instance, but
* the user can make a copy.
**/
simdjson_inline std::string_view str() const;
private:
// implementation details (subject to change)
/** Prints one character **/
simdjson_inline void one_char(char c);
/** Backing buffer **/
std::vector<char> buffer{}; // not ideal!
};
} // internal } // internal
namespace dom { namespace dom {
@@ -116,16 +146,9 @@ namespace dom {
* @param value The element. * @param value The element.
* @throw if there is an error with the underlying output stream. simdjson itself will not throw. * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
*/ */
inline std::ostream& operator<<(std::ostream& out, simdjson::dom::element value) { inline std::ostream& operator<<(std::ostream& out, simdjson::dom::element value);
simdjson::internal::string_builder<> sb;
sb.append(value);
return (out << sb.str());
}
#if SIMDJSON_EXCEPTIONS #if SIMDJSON_EXCEPTIONS
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::dom::element> x) { inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::dom::element> x);
if (x.error()) { throw simdjson::simdjson_error(x.error()); }
return (out << x.value());
}
#endif #endif
/** /**
* Print JSON to an output stream. * Print JSON to an output stream.
@@ -134,16 +157,9 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<sim
* @param value The array. * @param value The array.
* @throw if there is an error with the underlying output stream. simdjson itself will not throw. * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
*/ */
inline std::ostream& operator<<(std::ostream& out, simdjson::dom::array value) { inline std::ostream& operator<<(std::ostream& out, simdjson::dom::array value);
simdjson::internal::string_builder<> sb;
sb.append(value);
return (out << sb.str());
}
#if SIMDJSON_EXCEPTIONS #if SIMDJSON_EXCEPTIONS
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::dom::array> x) { inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::dom::array> x);
if (x.error()) { throw simdjson::simdjson_error(x.error()); }
return (out << x.value());
}
#endif #endif
/** /**
* Print JSON to an output stream. * Print JSON to an output stream.
@@ -152,16 +168,9 @@ inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<sim
* @param value The object. * @param value The object.
* @throw if there is an error with the underlying output stream. simdjson itself will not throw. * @throw if there is an error with the underlying output stream. simdjson itself will not throw.
*/ */
inline std::ostream& operator<<(std::ostream& out, simdjson::dom::object value) { inline std::ostream& operator<<(std::ostream& out, simdjson::dom::object value);
simdjson::internal::string_builder<> sb;
sb.append(value);
return (out << sb.str());
}
#if SIMDJSON_EXCEPTIONS #if SIMDJSON_EXCEPTIONS
inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::dom::object> x) { inline std::ostream& operator<<(std::ostream& out, simdjson::simdjson_result<simdjson::dom::object> x);
if (x.error()) { throw simdjson::simdjson_error(x.error()); }
return (out << x.value());
}
#endif #endif
} // namespace dom } // namespace dom
@@ -212,6 +221,38 @@ std::string minify(simdjson_result<T> x) {
} }
#endif #endif
/**
* Prettifies a JSON element or document, printing the valid JSON with indentation.
*
* dom::parser parser;
* element doc = parser.parse(" [ 1 , 2 , 3 ] "_padded);
*
* // Prints:
* // {
* // [
* // 1,
* // 2,
* // 3
* // ]
* // }
* cout << prettify(doc) << endl;
*
*/
template <class T>
std::string prettify(T x) {
simdjson::internal::string_builder<simdjson::internal::pretty_formatter> sb;
sb.append(x);
std::string_view answer = sb.str();
return std::string(answer.data(), answer.size());
}
#if SIMDJSON_EXCEPTIONS
template <class T>
std::string prettify(simdjson_result<T> x) {
if (x.error()) { throw simdjson_error(x.error()); }
return to_string(x.value());
}
#endif
} // namespace simdjson } // namespace simdjson
+5 -6
View File
@@ -1,11 +1,10 @@
#ifndef SIMDJSON_INLINE_ERROR_H #ifndef SIMDJSON_ERROR_INL_H
#define SIMDJSON_INLINE_ERROR_H #define SIMDJSON_ERROR_INL_H
#include <cstring>
#include <string>
#include <utility>
#include "simdjson/error.h" #include "simdjson/error.h"
#include <iostream>
namespace simdjson { namespace simdjson {
namespace internal { namespace internal {
// We store the error code so we can validate the error message is associated with the right code // We store the error code so we can validate the error message is associated with the right code
@@ -182,4 +181,4 @@ simdjson_inline simdjson_result<T>::simdjson_result() noexcept
} // namespace simdjson } // namespace simdjson
#endif // SIMDJSON_INLINE_ERROR_H #endif // SIMDJSON_ERROR_INL_H
+3 -1
View File
@@ -1,8 +1,10 @@
#ifndef SIMDJSON_ERROR_H #ifndef SIMDJSON_ERROR_H
#define SIMDJSON_ERROR_H #define SIMDJSON_ERROR_H
#include "simdjson/common_defs.h" #include "simdjson/base.h"
#include <string> #include <string>
#include <ostream>
namespace simdjson { namespace simdjson {
+2 -24
View File
@@ -1,30 +1,8 @@
#ifndef SIMDJSON_FALLBACK_H #ifndef SIMDJSON_FALLBACK_H
#define SIMDJSON_FALLBACK_H #define SIMDJSON_FALLBACK_H
#include "simdjson/implementation-base.h"
#if SIMDJSON_IMPLEMENTATION_FALLBACK
namespace simdjson {
/**
* Fallback implementation (runs on any machine).
*/
namespace fallback {
} // namespace fallback
} // namespace simdjson
#include "simdjson/fallback/implementation.h"
#include "simdjson/fallback/begin.h" #include "simdjson/fallback/begin.h"
#include "simdjson/generic/amalgamated.h"
// Declarations
#include "simdjson/generic/dom_parser_implementation.h"
#include "simdjson/fallback/bitmanipulation.h"
#include "simdjson/generic/jsoncharutils.h"
#include "simdjson/generic/atomparsing.h"
#include "simdjson/fallback/stringparsing.h"
#include "simdjson/fallback/numberparsing.h"
#include "simdjson/fallback/end.h" #include "simdjson/fallback/end.h"
#endif // SIMDJSON_IMPLEMENTATION_FALLBACK #endif // SIMDJSON_FALLBACK_H
#endif // SIMDJSON_FALLBACK_H
+19
View File
@@ -0,0 +1,19 @@
#ifndef SIMDJSON_FALLBACK_BASE_H
#define SIMDJSON_FALLBACK_BASE_H
#ifndef SIMDJSON_CONDITIONAL_INCLUDE
#include "simdjson/base.h"
#endif // SIMDJSON_CONDITIONAL_INCLUDE
namespace simdjson {
/**
* Fallback implementation (runs on any machine).
*/
namespace fallback {
class implementation;
} // namespace fallback
} // namespace simdjson
#endif // SIMDJSON_FALLBACK_BASE_H
+4
View File
@@ -1 +1,5 @@
#define SIMDJSON_IMPLEMENTATION fallback #define SIMDJSON_IMPLEMENTATION fallback
#include "simdjson/fallback/base.h"
#include "simdjson/fallback/bitmanipulation.h"
#include "simdjson/fallback/stringparsing_defs.h"
#include "simdjson/fallback/numberparsing_defs.h"

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