Compare commits

..

168 Commits

Author SHA1 Message Date
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
Daniel Lemire 82c9876aec Preparing release. 2023-01-21 18:07:06 -05:00
Daniel Lemire b9234be80f complete number_in_string for documents, stringify the version macro and improving trailing content errors (#1934)
* This completes the '*_in_string' support within documents.

* Minor updates.

* Additional fixes.
2023-01-21 15:29:08 -05:00
Daniel Lemire 0a2563e13e Testing and fixing log issues. (#1939)
* Testing and fixing log issues.

* Cleaning it a bit.
2023-01-21 15:28:56 -05:00
Daniel Lemire 727ec73c33 The fuzzer needs to be updated. (#1941) 2023-01-21 15:28:25 -05:00
Daniel Lemire 9a55a830ec Adding clang14 ci (#1940) 2023-01-21 15:27:21 -05:00
Daniel Lemire 8c89ae0cd9 Removing extra ';'. 2023-01-13 09:17:05 -05:00
Daniel Lemire 8c71ca1b1d Update implementation-selection.md 2023-01-07 13:43:26 -05:00
Daniel Lemire c72b4bc0f4 Update basics.md 2023-01-07 13:42:01 -05:00
Daniel Lemire 8a26cb3c8e Adding a couple of string tests. (#1935)
* Adding a couple of string tests.
2023-01-05 21:18:54 -05:00
Daniel Lemire bf2ba5c675 Update basics.md 2023-01-05 08:38:16 -05:00
Daniel Lemire f151300a76 Disabling fallback kernel on systems where it is not needed (#1930)
* Fixing issue 1772

* More cleaning.

* Allow disabling other kernels.

* Minor tweaks.
2023-01-03 09:52:41 -05:00
Daniel Lemire 9aa3563d99 Updating Google Benchmark. (#1929) 2023-01-03 09:52:26 -05:00
Daniel Lemire 9444c1a04f Merge branch 'master' of github.com:simdjson/simdjson 2022-12-19 21:07:17 -05:00
Daniel Lemire 883901a81b Updating users. 2022-12-19 21:07:07 -05:00
Daniel Lemire a2c96c9cca Update basics.md 2022-12-16 22:12:25 -05:00
Daniel Lemire c63da0ef2c Added a remark regarding assemblers. 2022-12-16 21:22:48 -05:00
Daniel Lemire c61cefda85 Merge branch 'master' of github.com:simdjson/simdjson 2022-12-05 12:25:52 -05:00
Daniel Lemire bffcbb444d Clarifying comment. 2022-12-05 12:25:29 -05:00
Daniel Lemire 0b2891aaab Trying fuzzer with llvm 14. (#1922) 2022-12-01 14:26:17 -05:00
wanweiqiangintel 983fb41802 Update README.md (#1925)
Add a real-word usage
2022-11-30 17:26:58 -05:00
Daniel Lemire 0d2455029d Preparing patch release. 2022-11-23 10:59:48 -05:00
Daniel Lemire e94f027310 Serialize 0 as 0.0 (#1921)
* Serialize 0 as 0.0

* Extending the '.0'.
2022-11-23 10:31:42 -05:00
sean 2b766e4c09 Fix: Add padded_string_view overload for parser::parse (#1916) 2022-11-23 09:22:39 -05:00
Daniel Lemire a5db75e1a6 Adding more development checks to the DOM front-end (#1915)
* This adds SIMDJSON_DEVELOPMENT_CHECKS to the DOM API to help users
in the scenario of issue 1914.

* More documentation and warnings.

* Updating following comments by Tyson
2022-10-17 09:11:09 -04:00
Daniel Lemire 4bd66cb891 We branch on GCC for performance. (#1913) 2022-10-16 13:15:35 -04:00
Daniel Lemire 960a7ebba1 Switching to iterate_many 2022-10-06 11:59:12 -04:00
Daniel Lemire d520062f8e Bumping API 2022-10-06 11:50:33 -04:00
Daniel Lemire db08d78ed0 Documents better the type method and makes is_null return an error condition in some instances (#1909) 2022-10-06 11:47:40 -04:00
Daniel Lemire 46292b8d4b Update basics.md 2022-10-05 08:50:52 -04:00
Tyson Andre 46241287c6 Check for trailing tokens in json2msgpack ondemand benchmark (#1908)
Related to #1904

Users of the simdjson library will see json2msgpack as an available
example of how to recursively process json with the ondemand parser,
and checking for trailing tokens in a document is one part of json validation.

These checks shouldn't affect benchmark results performance.
The benchmark is run on the 631KB twitter.json file.
2022-10-05 08:49:09 -04:00
Daniel Lemire 137cb14bcc Documenting how one can check for the end of the document. (#1907) 2022-10-04 20:23:52 -04:00
Daniel Lemire 5e6be3ed7a Minor fix (documentation and safety) regarding max. depth in ondemand. (#1906) 2022-10-04 12:24:20 -04:00
Tyson Andre c6ab52eebb [skip ci] Add an .editorconfig for .cpp/.h/.md for whitespace settings (#1901)
Make it less likely to accidentally introduce tabs, trailing whitespace,
carriage returns, non-utf8 in files, or files without trailing newlines.

https://editorconfig.org/ has plugins for various editors/IDEs and is
enabled by default in some IDEs.
2022-10-03 11:14:00 -04:00
Daniel Lemire a1aab1fafe Preparing release 2.2.3 2022-10-02 16:32:37 -04:00
Daniel Lemire b92cbbe280 Fixing issue 1898 (#1899)
* Fixing issue 1898 Preserve sign for number with underflowing exponent (#1900)


Before this commit, simdjson parsed "-1e-999" and "-0e-999" and "-1e-342"
as 0.0.
After this commit, those JSON strings get parsed as -0.0.
(https://en.wikipedia.org/wiki/Signed_zero)

The old behavior was inconsistent with the way simdjson parsed "-0.0" as -0.0.

Co-authored-by: Daniel Lemire <daniel@lemire.me>

Co-authored-by: Tyson Andre <tysonandre775@hotmail.com>
2022-10-02 16:25:39 -04:00
Tyson Andre 6d2a09f8e5 [skip ci] Fix typo, formatting nit in HACKING.md (#1902)
vim syntax highlighting doesn't work properly without space between a
bulleted list and the start of a code snippet.
2022-10-02 16:19:34 -04:00
Tyson Andre 00564bf7d5 Micro-optimization for parsing surrogate pairs (#1897)
Load 2 bytes and compare the 2 bytes against `"\u"`
Compilers with optimizations turned on will turn this into a 16-bit load
then 16-bit compare on supported platforms
(with smaller compiled code size).

Make it obvious to the compiler that it's reading two
consecutive bytes of the same pointer

Add parse_surrogate_pairs to show the difference exists.
See discussion in #1896
2022-10-02 12:10:53 -04:00
Tyson Andre 5809e51ae4 fix: Reject surrogate pairs with invalid low surrogate (#1896)
Closes #1894

Reject low surrogates outside of the range U+DC00—U+DFFF

Related to https://unicodebook.readthedocs.io/unicode_encodings.html#utf-16-surrogate-pairs

A surrogate pair should consist of a high surrogate and low surrogate.
They're used to represent 0x010000-0x10FFFF in the JSON spec because
the JavaScript specification originally only supported `\uXXXX`.

Previously, simdjson would accept some combinations of valid high
surrogates and invalid low surrogates due to a bug in the check.
(e.g. `\uD888\u1234` was accepted)

U+D800—U+DBFF (1,024 code points): high surrogates
U+DC00—U+DFFF (1,024 code points): low surrogates
2022-09-30 12:13:16 -04:00
Tyson Andre d27e7cce71 Fix typos in doc/basics.md (#1893) 2022-09-30 08:34:37 -04:00
David Korenchuk f7dc03f93d Fix documentation of description() method in implementation (#1895) 2022-09-30 08:34:06 -04:00
sean d4ac1b51d0 Fix various warnings & if constexpr (#1888) 2022-09-27 23:22:47 -04:00
Daniel Lemire 6a4222da71 Adding a remark to the documentation. 2022-09-19 15:28:33 -04:00
Daniel Lemire bba88eb5e5 Fixing typo in the documentation. 2022-09-19 10:21:11 -04:00
Daniel Lemire 16b3816455 This fixes an error caused by overeager gcc static analyser (#1891) 2022-09-19 10:20:48 -04:00
Andrea Pappacoda e5a408386b build: add pkg-config support (#1767)
* build: add pkg-config support

The CMake build script now generates a simple pkg-config files that can
be easily used by non-CMake users.

The file is generated from a template file that gets filled in at
configure time.

As CMake doesn't have anything similar to Meson's pkg-config generator
the file is quite static, i.e. new simdjson public defines/dependencies
won't be picked up automatically.

This approach also suffers from one minor issue, mentioned in
[jtojnar/cmake-snips][]; in short, it doesn't work well when users
specify CMAKE_INSTALL_INCLUDEDIR and similar as absolute paths. It's not
a big deal, and it will easily fixable once you'll require CMake >=3.20.

Fixes #1763

[jtojnar/cmake-snips]: https://github.com/jtojnar/cmake-snips#concatenating-paths-when-building-pkg-config-files

* build: handle absolute paths in .pc generation

As mentioned in the previous commit message, correct concatenation of
paths is only available in CMake >=3.20, so handling absolute paths in
pkg-config file generation requires using jtojnar's JoinPaths module.

* ci: add debian job

This new jobs compiles simdjson on Debian Testing, a semi-rolling
release, so that new compilers are always tested.

This job also tests the pkg-config file introduced in commit
1096c3b299
2022-08-26 16:20:51 -04:00
Herman Semenov e65f28e61a Fixed if condition, Win64 _fseeki64, trivial constructors C++11 (#1883) 2022-08-18 14:16:46 -04:00
Daniel Lemire fbb46b99e2 Fixes and verifies issue 1878. (#1880)
* Fixes and verifies issue 1878.

* Changing how NULL is handled.

* Different design.
2022-08-08 22:00:38 -04:00
Daniel Lemire 933c2ebeac Preparing release 2022-07-28 21:46:45 -04:00
Daniel Lemire db3e813aa6 Verifying and fixing issue 1876 (#1877)
* Verifying and fixing issue 1876

* Typo
2022-07-28 21:45:54 -04:00
Daniel Lemire 9c95a48fe6 cleaning on-demand benchmarks (#1875)
* Setting RapidJSON and yyjson to their latest version.

* Let us stop dumping all of the benchmarks (it is confusing) on screen.
2022-07-28 20:28:29 -04:00
Daniel Lemire cb20f7e7df Update CONTRIBUTING.md 2022-07-20 09:46:52 -04:00
Dirk Stolle 18b9168eec remove empty if block (#1873)
I guess it will be thrown away by the compiler's optimizer
anyway, but there is no need to keep this in the code.
2022-07-19 20:36:51 -04:00
Daniel Lemire 241ce7304c New version. 2022-07-19 16:47:06 -04:00
Daniel Lemire 5dbe96da96 We change slightly on development checks are enabled. (#1869)
* We change slightly on development checks are enabled.

* Removing garbagy code.
2022-07-19 16:40:02 -04:00
Daniel Lemire 40b397a3d4 Fixing issue 1870 (#1871) 2022-07-19 15:17:12 -04:00
strager 5510089d45 Improve build times for debug builds (#1859)
* Rename simdjson_really_inline -> simdjson_inline

I want to change the simdjson_really_inline macro to sometimes not force
inlining. After that upcoming change, the name simdjson_really_inline
will no longer makes sense.

Rename simdjson_really_inline to simdjson_inline. This patch should not
change semantics; simdjson_inline still forces inlining as before.

Some functions still need to be really inlined for ABI reasons.
(GCC's -Wpsabi complains otherwise.) Leave those functions marked as
simdjson_really_inline.

* Improve build times for debug builds

simdjson_inline is used for most simdjson functions. It forces inlining.
In unoptimized/debug builds, this can lead to a lot of machine code
being generated (especially with Address Sanitizer), causing slow
compilation.

Change simdjson_inline to force inlining only for optimized builds.

Sometimes, the programmer might want a slightly-optimized build and want
fast compilation (e.g. GCC's -Og mode). Allow simdjson users to define
the simdjson_inline macro themselves (e.g. on the command line:
-Dsimdjson_inline=inline) in cases where the default behavior is
undesired.

This patch reduced build times by over 75% for ondemand_object_tests.cpp
with GCC 9.4.0 and CMAKE_BUILD_TYPE=Debug on my AMD 5950X:

Before: 6.885 6.683 6.971 6.957 6.949 seconds (5 samples)
After:  1.492 1.551 1.494 1.490 1.531 seconds (5 samples)
2022-07-19 15:14:33 -04:00
Daniel Lemire 62a57907a7 Adding DOM benchmark to msgpack (#1866)
* We need simdjson dom for the json2msgpack benchmark

* Minor tweaking.
2022-07-14 13:47:10 -04:00
Daniel Lemire becbe99e81 Update README.md 2022-07-14 09:45:04 -04:00
Daniel Lemire bd3d67e889 Documenting a specific use case where you need a value if and only if it is another key is not present (#1865)
* Documenting a specific use case.

* Adding more comments and documentation.
2022-07-09 10:54:28 -04:00
Dirk Stolle a89d57d0d4 update dependency nlohmann/json for benchmarks to current version 3.10.5 (#1862) 2022-07-08 12:32:05 -04:00
Dirk Stolle e04d400c64 update jsoncpp to version 1.9.5 (#1863) 2022-07-08 12:31:43 -04:00
247 changed files with 13697 additions and 9031 deletions
+12
View File
@@ -0,0 +1,12 @@
# https://editorconfig.org/
root = true
# Conservatively avoid changing defaults for other file types, e.g. raw json files for test cases,
# Makefiles, etc.
[*.{cpp,h,md}]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
tab_width = 2
trim_trailing_whitespace = true
+1
View File
@@ -78,6 +78,7 @@
.gitattributes export-ignore
.gitignore export-ignore
.editorconfig export-ignore
# Sources
*.c text eol=lf diff=c
+8 -6
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
* 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
* 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**
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').
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 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.
**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.
@@ -51,6 +53,6 @@ We support up-to-date 64-bit ARM and x64 FreeBSD, macOS, Windows and Linux syste
**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
* HACKING guide: https://github.com/simdjson/simdjson/blob/master/HACKING.md
+33
View File
@@ -0,0 +1,33 @@
name: Debian
on: [push, pull_request]
defaults:
run:
shell: sh
permissions:
contents: read
jobs:
pkg-config:
runs-on: ubuntu-latest
container:
image: debian:testing
steps:
- uses: actions/checkout@v3
- name: Install dependencies
run: |
apt -y update
apt -y --no-install-recommends install g++ cmake make pkg-config
- name: Build and install
run: |
cmake -B build
cmake --build build
cmake --install build
- name: Test pkg-config
run: g++ examples/quickstart/quickstart.cpp $(pkg-config --cflags --libs simdjson)
+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
+7 -7
View File
@@ -24,7 +24,7 @@ jobs:
implementations: haswell westmere fallback
UBSAN_OPTIONS: halt_on_error=1
MAXLEN: -max_len=4000
CLANGVERSION: 11
CLANGVERSION: 15
# which optimization level to use for the sanitizer build (see build_fuzzer.variants.sh)
OPTLEVEL: -O3
@@ -32,7 +32,7 @@ jobs:
- name: Install packages necessary for building
run: |
sudo apt update
sudo apt-get install --quiet ninja-build valgrind zip unzip
sudo apt-get install --quiet ninja-build valgrind zip unzip lsb-release wget software-properties-common gnupg
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh $CLANGVERSION
@@ -50,12 +50,12 @@ jobs:
path: out/
key: corpus-${{ github.run_id }}
restore-keys: corpus-
- name: show statistics for the cached corpus
run: |
echo number of files in github action corpus cache:
find out -type f |wc -l
- name: Create and prepare the initial seed corpus
run: |
fuzz/build_corpus.sh
@@ -92,7 +92,7 @@ jobs:
export SIMDJSON_FORCE_IMPLEMENTATION=$implementation
build-sanitizers$OPTLEVEL/fuzz/fuzz_$fuzzer out/$fuzzer $others seedcorpus -max_total_time=20 $MAXLEN
done
echo now have $(ls out/$fuzzer |wc -l) files in corpus
echo now have $(ls out/$fuzzer |wc -l) files in corpus
done
- name: Fuzz differential impl. fuzzers with sanitizer+asserts (good at detecting errors)
@@ -119,7 +119,7 @@ jobs:
- name: Package the corpus into an artifact
run: |
for fuzzer in $defaultimplfuzzers $implfuzzers; do
for fuzzer in $defaultimplfuzzers $implfuzzers; do
tar rf corpus.tar out/$fuzzer
done
@@ -141,7 +141,7 @@ jobs:
run: |
for fuzzer in $defaultimplfuzzers $implfuzzers; do
find out/$fuzzer -type f |sort|head -n200|xargs -n40 valgrind build-replay/fuzz/fuzz_$fuzzer 2>&1|tee valgrind-$fuzzer.txt
done
done
- name: Compress the valgrind output
run: tar cf valgrind.tar valgrind-*.txt
+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)
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
+9 -2
View File
@@ -14,10 +14,17 @@ jobs:
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Use cmake
- name: Use cmake with address sanitizer
run: |
mkdir builddebug &&
cd builddebug &&
cmake -DSIMDJSON_SANITIZE=ON -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
cmake --build . &&
ctest -j --output-on-failure -LE explicitonly
ctest -j --output-on-failure -LE explicitonly
- 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 -j --output-on-failure -LE explicitonly
@@ -1,4 +1,4 @@
name: Ubuntu 18.04 CI (LLVM 7)
name: Ubuntu 22.04 CI (CLANG 14)
on: [push, pull_request]
@@ -7,25 +7,19 @@ jobs:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-18.04
env:
CC: clang-7
CXX: clang++-7
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: install clang 7
run: |
sudo apt update
sudo apt install clang-7
- name: Install clang++-14
run: sudo apt-get install -y clang++-14
- 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 .. &&
CXX=clang++-14 cmake -DSIMDJSON_DEVELOPER_MODE=ON .. &&
cmake --build . &&
ctest -j --output-on-failure -LE explicitonly
@@ -1,31 +1,30 @@
name: Macos (Xcode 11)
name: Ubuntu 22.04 CI (GCC 12, CXX 20)
on: [push, pull_request]
jobs:
macos-build:
ubuntu-build:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: macos-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Use cmake
run: |
xcversion select 11.7
mkdir builddebug &&
cd builddebug &&
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
CXX=g++-12 cmake -DSIMDJSON_CXX_STANDARD=20 -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
cmake --build . &&
ctest -j --output-on-failure -LE explicitonly &&
cd .. &&
mkdir build &&
cd build &&
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
CXX=g++-12 cmake -DSIMDJSON_CXX_STANDARD=20 -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
cmake --build . &&
ctest -j --output-on-failure -LE explicitonly &&
cmake --install . &&
@@ -1,25 +1,24 @@
name: Ubuntu 18.04 CI (GCC 7) with Thread Sanitizer
name: Ubuntu 22.04 CI GCC 12 with GLIBCXX_ASSERTIONS
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
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Install gcc12
run: sudo apt-get install -y g++-12
- 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
CXX=g++-12 cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GLIBCXX_ASSERTIONS=ON -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON .. &&
cmake --build . &&
ctest . -E avoid_
+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@v2
- 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
+2 -1
View File
@@ -96,6 +96,7 @@
"future": "cpp",
"queue": "cpp",
"shared_mutex": "cpp",
"ranges": "cpp"
"ranges": "cpp",
"span": "cpp"
}
}
+46 -8
View File
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
project(
simdjson
# The version number is modified by tools/release.py
VERSION 2.2.0
VERSION 3.2.0
DESCRIPTION "Parsing gigabytes of JSON per second"
HOMEPAGE_URL "https://simdjson.org/"
LANGUAGES CXX C
@@ -20,8 +20,8 @@ string(
# ---- Options, variables ----
# These version numbers are modified by tools/release.py
set(SIMDJSON_LIB_VERSION "13.0.0" CACHE STRING "simdjson library version")
set(SIMDJSON_LIB_SOVERSION "13" CACHE STRING "simdjson library soversion")
set(SIMDJSON_LIB_VERSION "16.0.0" CACHE STRING "simdjson library version")
set(SIMDJSON_LIB_SOVERSION "16" CACHE STRING "simdjson library soversion")
option(SIMDJSON_ENABLE_THREADS "Link with thread support" ON)
@@ -95,6 +95,21 @@ if(
)
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)
find_package(Threads REQUIRED)
simdjson_add_props(target_link_libraries PUBLIC Threads::Threads)
@@ -149,7 +164,25 @@ install(
EXPORT simdjsonTargets
NAMESPACE simdjson::
DESTINATION "${SIMDJSON_INSTALL_CMAKEDIR}"
COMPONENT example_Development
COMPONENT simdjson_Development
)
# pkg-config
include(cmake/JoinPaths.cmake)
join_paths(PKGCONFIG_INCLUDEDIR "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
join_paths(PKGCONFIG_LIBDIR "\${prefix}" "${CMAKE_INSTALL_LIBDIR}")
if(SIMDJSON_ENABLE_THREADS)
set(PKGCONFIG_CFLAGS "-DSIMDJSON_THREADS_ENABLED=1")
if(CMAKE_THREAD_LIBS_INIT)
set(PKGCONFIG_LIBS_PRIVATE "Libs.private: ${CMAKE_THREAD_LIBS_INIT}")
endif()
endif()
configure_file("simdjson.pc.in" "simdjson.pc" @ONLY)
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/simdjson.pc"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig"
)
#
@@ -170,11 +203,14 @@ endif()
# ---- 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)
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()
elseif(NOT is_top_project)
message(AUTHOR_WARNING "Developer mode is intended for developers of simdjson")
endif()
simdjson_apply_props(simdjson-internal-flags)
@@ -215,7 +251,9 @@ add_subdirectory(singleheader)
#
add_subdirectory(tests)
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)
#
+1 -1
View File
@@ -54,7 +54,7 @@ Contributors are encouraged to :
- Document their changes. Though we do not enforce a rule regarding code comments, we prefer that non-trivial algorithms and techniques be somewhat documented in the code.
- Follow as much as possible the existing code style. We do not enforce a specific code style, but we prefer consistency.
- Modify as few lines of code as possible when working on an issue. The more lines you modify, the harder it is for your fellow human beings to understand what is going on.
- Tools may report "problems" with the code, but we never delegate programming to tools: if there is a problem with the code, we need to understand it. Thus we will not "fix" code merely to please a static analyzer if we do not understand.
- Tools may report "problems" with the code, but we never delegate programming to tools: if there is a problem with the code, we need to understand it. Thus we will not "fix" code merely to please a static analyzer.
- Provide tests for any new feature. We will not merge a new feature without tests.
Pull Requests
+11 -5
View File
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = "2.2.0"
PROJECT_NUMBER = "3.2.0"
# 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
@@ -829,7 +829,7 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# 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
# 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.
# 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
# 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.
# 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
# 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.
# 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
# doxygen will group on one line in the generated HTML documentation.
+18 -5
View File
@@ -1,3 +1,4 @@
Hacking simdjson
================
@@ -6,6 +7,16 @@ 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.
- [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)](#usage-cmake-on-64-bit-windows-using-visual-studio-2019)
- [Various References](#various-references)
Design notes
------------------------------
@@ -82,7 +93,7 @@ Other important files and directories:
* **singleheader/amalgamate.py:** Generates `singleheader/simdjson.h` and `singleheader/simdjson.cpp` for release (python script).
* **benchmark:** This is where we do benchmarking. Benchmarking is core to every change we make; the
cardinal rule is don't regress performance without knowing exactly why, and what you're trading
for it. Many of our benchmarks are microbenchmarks. We are effectively doing controlled scientific experiments for the purpose of understanding what affects our performance. So we simplify as much as possible. We try to avoid irrelevant factors such as page faults, interrupts, unnnecessary system calls. We recommend checking the performance as follows:
for it. Many of our benchmarks are microbenchmarks. We are effectively doing controlled scientific experiments for the purpose of understanding what affects our performance. So we simplify as much as possible. We try to avoid irrelevant factors such as page faults, interrupts, unnecessary system calls. We recommend checking the performance as follows:
```bash
mkdir build
cd build
@@ -114,7 +125,7 @@ Other important files and directories:
* `json2json mydoc.json` parses the document, constructs a model and then dumps back the result to standard output.
* `json2json -d mydoc.json` parses the document, constructs a model and then dumps model (as a tape) to standard output. The tape format is described in the accompanying file `tape.md`.
* `minify mydoc.json` minifies the JSON document, outputting the result to standard output. Minifying means to remove the unneeded white space characters.
*`jsonpointer mydoc.json <jsonpath> <jsonpath> ... <jsonpath>` parses the document, constructs a model and then processes a series of [JSON Pointer paths](https://tools.ietf.org/html/rfc6901). The result is itself a JSON document.
* `jsonpointer mydoc.json <jsonpath> <jsonpath> ... <jsonpath>` parses the document, constructs a model and then processes a series of [JSON Pointer paths](https://tools.ietf.org/html/rfc6901). The result is itself a JSON document.
> **Don't modify the files in singleheader/ directly; these are automatically generated.**
@@ -193,7 +204,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
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.
@@ -256,7 +267,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.
@@ -285,7 +298,7 @@ Furthermore, if you have installed LLVM clang on Windows, for example as a compo
- `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)
- [Parsing JSON is a Minefield 💣](http://seriot.ch/parsing_json.php)
+1 -1
View File
@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2018-2019 The simdjson authors
Copyright 2018-2023 The simdjson authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
+43 -21
View File
@@ -1,9 +1,11 @@
![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)
![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] [![Doxygen Documentation](https://img.shields.io/badge/docs-doxygen-green.svg)](https://simdjson.org/api/2.0.0/index.html)
[![][license img]][license]
[![Doxygen Documentation](https://img.shields.io/badge/docs-doxygen-green.svg)](https://simdjson.github.io/simdjson/)
simdjson : Parsing gigabytes of JSON per second
===============================================
@@ -26,16 +28,38 @@ This library is part of the [Awesome Modern C++](https://awesomecpp.com) list.
Table of Contents
-----------------
* [Real-world usage](#real-world-usage)
* [Quick Start](#quick-start)
* [Documentation](#documentation)
* [Performance results](#performance-results)
* [Real-world usage](#real-world-usage)
* [Bindings and Ports of simdjson](#bindings-and-ports-of-simdjson)
* [About simdjson](#about-simdjson)
* [Funding](#funding)
* [Contributing to simdjson](#contributing-to-simdjson)
* [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)
If you are planning to use simdjson in a product, please work from one of our releases.
Quick Start
-----------
@@ -62,13 +86,13 @@ int main(void) {
ondemand::document tweets = parser.iterate(json);
std::cout << uint64_t(tweets["search_metadata"]["count"]) << " results." << std::endl;
}
```
```
3. `c++ -o quickstart quickstart.cpp simdjson.cpp`
4. `./quickstart`
```
```
100 results.
```
```
Documentation
-------------
@@ -79,7 +103,13 @@ Usage documentation is available:
* [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
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
-------------------
@@ -108,17 +138,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)
If you are planning to use simdjson in a product, please work from one of our releases.
Bindings and Ports of simdjson
------------------------------
@@ -139,9 +158,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.
- [rcppsimdjson](https://github.com/eddelbuettel/rcppsimdjson): R 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.
- [hermes-json](https://hackage.haskell.org/package/hermes-json): haskell bindings.
- [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
--------------
@@ -184,7 +206,7 @@ License
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.
-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.
@@ -15,11 +15,11 @@ using namespace json_benchmark;
struct brand {
double cumulative_rating;
uint64_t reviews_count;
simdjson_really_inline bool operator==(const brand &other) const {
simdjson_inline bool operator==(const brand &other) const {
return cumulative_rating == other.cumulative_rating &&
reviews_count == other.reviews_count;
}
simdjson_really_inline bool operator!=(const brand &other) const { return !(*this == other); }
simdjson_inline bool operator!=(const brand &other) const { return !(*this == other); }
};
simdjson_unused static std::ostream &operator<<(std::ostream &o, const brand &b) {
@@ -66,8 +66,8 @@ struct runner : public file_runner<I> {
template<bool threaded>
struct simdjson_dom;
template<typename I> simdjson_really_inline static void amazon_cellphones(benchmark::State &state) {
template<typename I> simdjson_inline static void amazon_cellphones(benchmark::State &state) {
run_json_benchmark<runner<I>, runner<simdjson_dom<UNTHREADED>>>(state);
}
} // namespace amazon_cellphones
} // namespace amazon_cellphones
+28 -3
View File
@@ -521,7 +521,7 @@ static void twitter_image_sizes(State& state) {
set<tuple<uint64_t, uint64_t>> image_sizes;
for (dom::object tweet : doc["statuses"]) {
dom::array media;
if (not (error = tweet["entities"]["media"].get(media))) {
if (! (error = tweet["entities"]["media"].get(media))) {
for (dom::object image : media) {
for (auto size : image["sizes"].get_object()) {
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) {
dom::object user;
if ((error = tweet["user"].get(user))) { return; }
bool default_profile;
bool default_profile{};
if ((error = user["default_profile"].get(default_profile))) { return; }
if (default_profile) {
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; }
for (dom::element tweet : statuses) {
dom::array images;
if (not (error = tweet["entities"]["media"].get(images))) {
if (! (error = tweet["entities"]["media"].get(images))) {
for (dom::element image : images) {
dom::object sizes;
if ((error = image["sizes"].get(sizes))) { return; }
@@ -656,6 +656,31 @@ static void error_code_twitter_image_sizes(State& state) noexcept {
}
BENCHMARK(error_code_twitter_image_sizes);
static void parse_surrogate_pairs(State& state) {
// NOTE: This mostly exists to show there's a tiny benefit to
// loading and comparing both bytes of "\\u" simultaneously.
// (which should also reduce the compiled code size).
// The repeated surrogate pairs make this easier to measure.
dom::parser parser;
const std::string_view data = "\"\\uD834\\uDD1E\\uD834\\uDD1E\\uD834\\uDD1E\\uD834\\uDD1E\\uD834\\uDD1E\\uD834\\uDD1E\\uD834\\uDD1E\\uD834\\uDD1E\\uD834\\uDD1E\\uD834\\uDD1E\"";
padded_string docdata{data};
// we do not want mem. alloc. in the loop.
auto error = parser.allocate(docdata.size());
if (error) {
cout << error << endl;
return;
}
for (simdjson_unused auto _ : state) {
dom::element doc;
if ((error = parser.parse(docdata).get(doc))) {
cerr << "could not parse string" << error << endl;
return;
}
}
}
BENCHMARK(parse_surrogate_pairs);
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
SIMDJSON_PUSH_DISABLE_WARNINGS
+101 -58
View File
@@ -26,72 +26,115 @@ SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
SIMDJSON_POP_DISABLE_WARNINGS
#include "json2msgpack/simdjson_ondemand.h"
#include "json2msgpack/rapidjson.h"
#include "json2msgpack/simdjson_dom.h"
#include "json2msgpack/yyjson.h"
#include "json2msgpack/rapidjson.h"
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "json2msgpack/sajson.h"
#endif // SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "json2msgpack/nlohmann_json.h"
#include "partial_tweets/simdjson_ondemand.h"
#include "partial_tweets/simdjson_dom.h"
#include "partial_tweets/yyjson.h"
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "partial_tweets/sajson.h"
#endif // SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "partial_tweets/rapidjson.h"
#if SIMDJSON_COMPETITION_SAX
#include "partial_tweets/rapidjson_sax.h"
#endif // SIMDJSON_COMPETITION_SAX
#include "partial_tweets/nlohmann_json.h"
#if SIMDJSON_COMPETITION_SAX
#include "partial_tweets/nlohmann_json_sax.h"
#endif // SIMDJSON_COMPETITION_SAX
#include "distinct_user_id/simdjson_ondemand.h"
#include "distinct_user_id/simdjson_ondemand_json_pointer.h"
#include "distinct_user_id/simdjson_dom.h"
#include "distinct_user_id/simdjson_dom_json_pointer.h"
#include "distinct_user_id/yyjson.h"
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "distinct_user_id/sajson.h"
#endif // SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "distinct_user_id/rapidjson.h"
#if SIMDJSON_COMPETITION_SAX
#include "distinct_user_id/rapidjson_sax.h"
#endif // SIMDJSON_COMPETITION_SAX
#include "distinct_user_id/nlohmann_json.h"
#if SIMDJSON_COMPETITION_SAX
#include "distinct_user_id/nlohmann_json_sax.h"
#endif // SIMDJSON_COMPETITION_SAX
#include "find_tweet/simdjson_ondemand.h"
#include "find_tweet/simdjson_dom.h"
#include "find_tweet/yyjson.h"
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "find_tweet/sajson.h"
#endif // SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "find_tweet/rapidjson.h"
#if SIMDJSON_COMPETITION_SAX
#include "find_tweet/rapidjson_sax.h"
#endif // SIMDJSON_COMPETITION_SAX
#include "find_tweet/nlohmann_json.h"
#if SIMDJSON_COMPETITION_SAX
#include "find_tweet/nlohmann_json_sax.h"
#endif // SIMDJSON_COMPETITION_SAX
#include "top_tweet/simdjson_ondemand.h"
#include "top_tweet/simdjson_dom.h"
#include "top_tweet/yyjson.h"
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "top_tweet/sajson.h"
#endif // SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "top_tweet/rapidjson.h"
#if SIMDJSON_COMPETITION_SAX
#include "top_tweet/rapidjson_sax.h"
#endif // SIMDJSON_COMPETITION_SAX
#include "top_tweet/nlohmann_json.h"
#if SIMDJSON_COMPETITION_SAX
#include "top_tweet/nlohmann_json_sax.h"
#endif // SIMDJSON_COMPETITION_SAX
#include "kostya/simdjson_ondemand.h"
#include "kostya/simdjson_dom.h"
#include "kostya/yyjson.h"
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "kostya/sajson.h"
#endif // SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "kostya/rapidjson.h"
#if SIMDJSON_COMPETITION_SAX
#include "kostya/rapidjson_sax.h"
#endif // SIMDJSON_COMPETITION_SAX
#include "kostya/nlohmann_json.h"
#if SIMDJSON_COMPETITION_SAX
#include "kostya/nlohmann_json_sax.h"
#endif // SIMDJSON_COMPETITION_SAX
#include "large_random/simdjson_ondemand.h"
#if SIMDJSON_COMPETITION_ONDEMAND_UNORDERED
#include "large_random/simdjson_ondemand_unordered.h"
#endif // SIMDJSON_COMPETITION_ONDEMAND_UNORDERED
#include "large_random/simdjson_dom.h"
#include "large_random/yyjson.h"
#if SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "large_random/sajson.h"
#endif // SIMDJSON_COMPETITION_ONDEMAND_SAJSON
#include "large_random/rapidjson.h"
#if SIMDJSON_COMPETITION_SAX
#include "large_random/rapidjson_sax.h"
#endif // SIMDJSON_COMPETITION_SAX
#include "large_random/nlohmann_json.h"
#if SIMDJSON_COMPETITION_SAX
#include "large_random/nlohmann_json_sax.h"
#endif // SIMDJSON_COMPETITION_SAX
#include "amazon_cellphones/simdjson_dom.h"
#include "amazon_cellphones/simdjson_ondemand.h"
#include "large_amazon_cellphones/simdjson_dom.h"
#include "large_amazon_cellphones/simdjson_ondemand.h"
#include "partial_tweets/simdjson_dom.h"
#include "partial_tweets/simdjson_ondemand.h"
#include "partial_tweets/yyjson.h"
#include "partial_tweets/sajson.h"
#include "partial_tweets/rapidjson.h"
#include "partial_tweets/rapidjson_sax.h"
#include "partial_tweets/nlohmann_json.h"
#include "partial_tweets/nlohmann_json_sax.h"
#include "large_random/simdjson_dom.h"
#include "large_random/simdjson_ondemand.h"
#include "large_random/simdjson_ondemand_unordered.h"
#include "large_random/yyjson.h"
#include "large_random/sajson.h"
#include "large_random/rapidjson.h"
#include "large_random/rapidjson_sax.h"
#include "large_random/nlohmann_json.h"
#include "large_random/nlohmann_json_sax.h"
#include "kostya/simdjson_dom.h"
#include "kostya/simdjson_ondemand.h"
#include "kostya/yyjson.h"
#include "kostya/sajson.h"
#include "kostya/rapidjson.h"
#include "kostya/rapidjson_sax.h"
#include "kostya/nlohmann_json.h"
#include "kostya/nlohmann_json_sax.h"
#include "distinct_user_id/simdjson_dom.h"
#include "distinct_user_id/simdjson_dom_json_pointer.h"
#include "distinct_user_id/simdjson_ondemand.h"
#include "distinct_user_id/simdjson_ondemand_json_pointer.h"
#include "distinct_user_id/yyjson.h"
#include "distinct_user_id/sajson.h"
#include "distinct_user_id/rapidjson.h"
#include "distinct_user_id/rapidjson_sax.h"
#include "distinct_user_id/nlohmann_json.h"
#include "distinct_user_id/nlohmann_json_sax.h"
#include "find_tweet/simdjson_dom.h"
#include "find_tweet/simdjson_ondemand.h"
#include "find_tweet/yyjson.h"
#include "find_tweet/sajson.h"
#include "find_tweet/rapidjson.h"
#include "find_tweet/rapidjson_sax.h"
#include "find_tweet/nlohmann_json.h"
#include "find_tweet/nlohmann_json_sax.h"
#include "top_tweet/simdjson_dom.h"
#include "top_tweet/simdjson_ondemand.h"
#include "top_tweet/yyjson.h"
#include "top_tweet/sajson.h"
#include "top_tweet/rapidjson.h"
#include "top_tweet/rapidjson_sax.h"
#include "top_tweet/nlohmann_json.h"
#include "top_tweet/nlohmann_json_sax.h"
BENCHMARK_MAIN();
+1 -1
View File
@@ -164,7 +164,7 @@ struct feature_benchmarker {
}
simdjson_really_inline void run_iterations(size_t iterations, bool stage1_only=false) {
simdjson_inline void run_iterations(size_t iterations, bool stage1_only=false) {
struct7.run_iterations(iterations, stage1_only);
struct7_miss.run_iterations(iterations, stage1_only);
struct7_full.run_iterations(iterations, stage1_only);
+3 -3
View File
@@ -308,7 +308,7 @@ struct benchmarker {
return all_stages_without_allocation.iterations;
}
simdjson_really_inline void run_iteration(bool stage1_only, bool hotbuffers=false) {
simdjson_inline void run_iteration(bool stage1_only, bool hotbuffers=false) {
// Allocate dom::parser
collector.start();
dom::parser parser;
@@ -384,7 +384,7 @@ struct benchmarker {
loop << all_loop_count;
}
simdjson_really_inline void run_iterations(size_t iterations, bool stage1_only, bool hotbuffers=false) {
simdjson_inline void run_iterations(size_t iterations, bool stage1_only, bool hotbuffers=false) {
for (size_t i = 0; i<iterations; i++) {
run_iteration(stage1_only, hotbuffers);
}
@@ -520,7 +520,7 @@ struct benchmarker {
double freqall = (all_stages_without_allocation.best.cycles() / all_stages_without_allocation.best.elapsed_sec()) / 1000000000.0;
double freqmin = min(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"
"Range for stage 1 and stage 2 : [%.3f GHz, %.3f GHz], overall: %.3f GHz.\n",
freqmin, freqmax, freqall);
@@ -46,7 +46,7 @@ struct runner : public file_runner<I> {
struct simdjson_dom;
template<typename I> simdjson_really_inline static void distinct_user_id(benchmark::State &state) {
template<typename I> simdjson_inline static void distinct_user_id(benchmark::State &state) {
run_json_benchmark<runner<I>, runner<simdjson_dom>>(state);
}
+2 -1
View File
@@ -46,13 +46,14 @@ struct rapidjson : rapidjson_base {
};
BENCHMARK_TEMPLATE(distinct_user_id, rapidjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
struct rapidjson_insitu : rapidjson_base {
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), result);
}
};
BENCHMARK_TEMPLATE(distinct_user_id, rapidjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace partial_tweets
#endif // SIMDJSON_COMPETITION_RAPIDJSON
+2 -2
View File
@@ -11,12 +11,12 @@ struct sajson {
size_t *ast_buffer{nullptr};
~sajson() { free(ast_buffer); }
simdjson_really_inline std::string_view get_string_view(const ::sajson::value &obj, std::string_view key) {
simdjson_inline std::string_view get_string_view(const ::sajson::value &obj, std::string_view key) {
auto val = obj.get_value_of_key({key.data(), key.length()});
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field is not a string"; }
return { val.as_cstring(), val.get_string_length() };
}
simdjson_really_inline uint64_t get_str_uint64(const ::sajson::value &obj, std::string_view key) {
simdjson_inline uint64_t get_str_uint64(const ::sajson::value &obj, std::string_view key) {
// Since sajson only supports 53-bit numbers, and IDs in twitter.json can be > 53 bits, we read the corresponding id_str and parse that.
auto val = obj.get_value_of_key({key.data(), key.length()});
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field not a string"; }
+2 -1
View File
@@ -49,13 +49,14 @@ struct yyjson : yyjson_base {
};
BENCHMARK_TEMPLATE(distinct_user_id, yyjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
struct yyjson_insitu : yyjson_base {
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
return yyjson_base::run(yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0), result);
}
};
BENCHMARK_TEMPLATE(distinct_user_id, yyjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace distinct_user_id
#endif // SIMDJSON_COMPETITION_YYJSON
+1 -1
View File
@@ -41,7 +41,7 @@ using stat_t = struct stat_s;
simdjson_really_inline void simdjson_process_atom(stat_t &s,
simdjson_inline void simdjson_process_atom(stat_t &s,
simdjson::dom::element element) {
if (element.is<int64_t>()) {
s.integer_count++;
+4 -4
View File
@@ -134,7 +134,7 @@ struct event_collector {
#if defined(__linux__)
LinuxEvents<PERF_TYPE_HARDWARE> linux_events;
event_collector(bool quiet = false) : linux_events(vector<int>{
event_collector(simdjson_unused bool quiet = false) : linux_events(vector<int>{
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
PERF_COUNT_HW_CPU_CYCLES,
PERF_COUNT_HW_INSTRUCTIONS,
@@ -145,7 +145,7 @@ struct event_collector {
PERF_COUNT_HW_CACHE_REFERENCES,
PERF_COUNT_HW_CACHE_MISSES
#endif
}, quiet) {}
}) {}
bool has_events() {
return linux_events.is_working();
}
@@ -156,13 +156,13 @@ struct event_collector {
}
#endif
simdjson_really_inline void start() {
simdjson_inline void start() {
#if defined(__linux)
linux_events.start();
#endif
start_clock = steady_clock::now();
}
simdjson_really_inline event_count& end() {
simdjson_inline event_count& end() {
time_point<steady_clock> end_clock = steady_clock::now();
#if defined(__linux)
linux_events.end(count.event_counts);
+1 -1
View File
@@ -33,7 +33,7 @@ struct runner : public file_runner<I> {
struct simdjson_dom;
template<typename I> simdjson_really_inline static void find_tweet(benchmark::State &state) {
template<typename I> simdjson_inline static void find_tweet(benchmark::State &state) {
run_json_benchmark<runner<I>, runner<simdjson_dom>>(state);
}
+2 -1
View File
@@ -40,13 +40,14 @@ struct rapidjson : rapidjson_base {
};
BENCHMARK_TEMPLATE(find_tweet, rapidjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
struct rapidjson_insitu : rapidjson_base {
bool run(simdjson::padded_string &json, uint64_t find_id, std::string_view &result) {
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), find_id, result);
}
};
BENCHMARK_TEMPLATE(find_tweet, rapidjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace find_tweet
#endif // SIMDJSON_COMPETITION_RAPIDJSON
+2 -2
View File
@@ -13,12 +13,12 @@ struct sajson {
size_t *ast_buffer{nullptr};
~sajson() { free(ast_buffer); }
simdjson_really_inline std::string_view get_string_view(const ::sajson::value &obj, std::string_view key) {
simdjson_inline std::string_view get_string_view(const ::sajson::value &obj, std::string_view key) {
auto val = obj.get_value_of_key({key.data(), key.length()});
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field is not a string"; }
return { val.as_cstring(), val.get_string_length() };
}
simdjson_really_inline uint64_t get_str_uint64(const ::sajson::value &obj, std::string_view key) {
simdjson_inline uint64_t get_str_uint64(const ::sajson::value &obj, std::string_view key) {
// Since sajson only supports 53-bit numbers, and IDs in twitter.json can be > 53 bits, we read the corresponding id_str and parse that.
auto val = obj.get_value_of_key({key.data(), key.length()});
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field not a string"; }
+2 -2
View File
@@ -40,14 +40,14 @@ struct yyjson : yyjson_base {
}
};
BENCHMARK_TEMPLATE(find_tweet, yyjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
struct yyjson_insitu : yyjson_base {
bool run(simdjson::padded_string &json, uint64_t find_id, std::string_view &result) {
return yyjson_base::run(yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0), find_id, result);
}
};
BENCHMARK_TEMPLATE(find_tweet, yyjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace find_tweet
#endif // SIMDJSON_COMPETITION_YYJSON
+2 -2
View File
@@ -41,8 +41,8 @@ template <typename I> struct runner : public file_runner<I> {
struct simdjson_ondemand;
template <typename I>
simdjson_really_inline static void json2msgpack(benchmark::State &state) {
simdjson_inline static void json2msgpack(benchmark::State &state) {
run_json_benchmark<runner<I>, runner<simdjson_ondemand>>(state);
}
} // namespace json2msgpack
} // namespace json2msgpack
+9 -7
View File
@@ -122,19 +122,21 @@ struct rapidjson_base {
};
using rapidjson_lossless = rapidjson_base<kParseValidateEncodingFlag|kParseFullPrecisionFlag>;
BENCHMARK_TEMPLATE(json2msgpack, rapidjson_lossless)->UseManualTime();
using rapidjson = rapidjson_base<kParseValidateEncodingFlag>;
using rapidjson = rapidjson_base<kParseValidateEncodingFlag|kParseFullPrecisionFlag>;
BENCHMARK_TEMPLATE(json2msgpack, rapidjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_APPROX
using rapidjson_approx = rapidjson_base<kParseValidateEncodingFlag>;
BENCHMARK_TEMPLATE(json2msgpack, rapidjson_approx)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_APPROX
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
using rapidjson_insitu = rapidjson_base<kParseValidateEncodingFlag|kParseInsituFlag>;
BENCHMARK_TEMPLATE(json2msgpack, rapidjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace json2msgpack
#endif // SIMDJSON_COMPETITION_RAPIDJSON
+138
View File
@@ -0,0 +1,138 @@
#pragma once
#if SIMDJSON_EXCEPTIONS
#include "json2msgpack.h"
namespace json2msgpack {
using namespace simdjson;
struct simdjsondom2msgpack {
/**
* @brief Converts the provided JSON into msgpack.
*
* @param json JSON input
* @param buf temporary buffer (must be large enough, with simdjson::SIMDJSON_PADDING bytes
* of padding)
* @return std::string_view msgpack output, writting to the temporary buffer
*/
inline std::string_view to_msgpack(const simdjson::padded_string &json,
uint8_t *buf);
private:
simdjson_really_inline void write_double(const double d) noexcept;
simdjson_really_inline void write_string(const std::string_view v) noexcept;
simdjson_really_inline void write_byte(const uint8_t b) noexcept;
simdjson_really_inline void write_uint32(const uint32_t w) noexcept;
simdjson_really_inline uint8_t *skip_uint32() noexcept;
simdjson_really_inline void write_uint32_at(const uint32_t w,
uint8_t *p) noexcept;
inline void recursive_processor(simdjson::dom::element element);
dom::parser parser;
uint8_t *buff{};
};
std::string_view
simdjsondom2msgpack::to_msgpack(const simdjson::padded_string &json,
uint8_t *buf) {
buff = buf;
recursive_processor(parser.parse(json));
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
}
void simdjsondom2msgpack::write_string(const std::string_view v) noexcept {
write_byte(0xdb);
write_uint32(uint32_t(v.size()));
::memcpy(buff, v.data(), v.size());
buff += v.size();
}
void simdjsondom2msgpack::write_double(const double d) noexcept {
*buff++ = 0xcb;
::memcpy(buff, &d, sizeof(d));
buff += sizeof(d);
}
void simdjsondom2msgpack::write_byte(const uint8_t b) noexcept {
*buff = b;
buff++;
}
void simdjsondom2msgpack::write_uint32(const uint32_t w) noexcept {
::memcpy(buff, &w, sizeof(w));
buff += sizeof(w);
}
uint8_t *simdjsondom2msgpack::skip_uint32() noexcept {
uint8_t *ret = buff;
buff += sizeof(uint32_t);
return ret;
}
void simdjsondom2msgpack::write_uint32_at(const uint32_t w, uint8_t *p) noexcept {
::memcpy(p, &w, sizeof(w));
}
void simdjsondom2msgpack::recursive_processor(simdjson::dom::element element) {
switch (element.type()) {
case dom::element_type::ARRAY: {
uint32_t counter = 0;
write_byte(0xdd);
uint8_t *location = skip_uint32();
for (auto child : dom::array(element)) {
counter++;
recursive_processor(child);
}
write_uint32_at(counter, location);}
break;
case dom::element_type::OBJECT:{
uint32_t counter = 0;
write_byte(0xdf);
uint8_t *location = skip_uint32();
for (dom::key_value_pair field : dom::object(element)) {
counter++;
write_string(field.key);
recursive_processor(field.value);
}
write_uint32_at(counter, location);
}
break;
case dom::element_type::INT64:
case dom::element_type::UINT64:
case dom::element_type::DOUBLE:
write_double( double(element));
break;
case dom::element_type::STRING:
write_string(std::string_view(element));
break;
case dom::element_type::BOOL:
write_byte(0xc2 + bool(element));
break;
case dom::element_type::NULL_VALUE:
write_byte(0xc0);
break;
default:
break;
}
}
struct simdjson_dom {
using StringType = std::string_view;
simdjsondom2msgpack parser{};
bool run(simdjson::padded_string &json, char *buffer,
std::string_view &result) {
result = parser.to_msgpack(json, reinterpret_cast<uint8_t *>(buffer));
return true;
}
};
BENCHMARK_TEMPLATE(json2msgpack, simdjson_dom)->UseManualTime();
} // namespace json2msgpack
#endif // SIMDJSON_EXCEPTIONS
+78 -11
View File
@@ -42,18 +42,18 @@ struct simdjson2msgpack {
uint8_t *buf);
private:
simdjson_really_inline void write_double(const double d) noexcept;
simdjson_really_inline void write_byte(const uint8_t b) noexcept;
simdjson_really_inline void write_uint32(const uint32_t w) noexcept;
simdjson_really_inline uint8_t *skip_uint32() noexcept;
simdjson_really_inline void write_uint32_at(const uint32_t w,
simdjson_inline void write_double(const double d) noexcept;
simdjson_inline void write_byte(const uint8_t b) noexcept;
simdjson_inline void write_uint32(const uint32_t w) noexcept;
simdjson_inline uint8_t *skip_uint32() noexcept;
simdjson_inline void write_uint32_at(const uint32_t w,
uint8_t *p) noexcept;
simdjson_really_inline void
simdjson_inline void
write_raw_string(simdjson::ondemand::raw_json_string rjs);
inline void recursive_processor(simdjson::ondemand::value element);
inline void recursive_processor_ref(simdjson::ondemand::value& element);
simdjson::ondemand::parser parser;
simdjson::ondemand::document doc;
uint8_t *buff{};
};
@@ -75,17 +75,33 @@ simdjson2msgpack::to_msgpack(const simdjson::padded_string &json,
write_byte(0xc2 + doc.get_bool());
break;
case simdjson::ondemand::json_type::null:
write_byte(0xc0);
// We check that the value is indeed null
// otherwise: an error is thrown.
if(doc.is_null()) {
write_byte(0xc0);
}
break;
case simdjson::ondemand::json_type::array:
case simdjson::ondemand::json_type::object:
default:
// impossible
break;
SIMDJSON_UNREACHABLE();
}
} else {
simdjson::ondemand::value val = doc;
#define SIMDJSON_GCC_COMPILER ((__GNUC__) && !(__clang__) && !(__INTEL_COMPILER))
#if SIMDJSON_GCC_COMPILER
// the GCC compiler does well with by-value passing.
// GCC has superior recursive inlining:
// https://stackoverflow.com/questions/29186186/why-does-gcc-generate-a-faster-program-than-clang-in-this-recursive-fibonacci-co
// https://godbolt.org/z/TeK4doE51
recursive_processor(val);
#else
recursive_processor_ref(val);
#endif
}
if (!doc.at_end()) {
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));
}
@@ -157,7 +173,58 @@ void simdjson2msgpack::recursive_processor(simdjson::ondemand::value element) {
write_byte(0xc2 + element.get_bool());
break;
case simdjson::ondemand::json_type::null:
write_byte(0xc0);
// We check that the value is indeed null
// otherwise: an error is thrown.
if(element.is_null()) {
write_byte(0xc0);
}
break;
default:
SIMDJSON_UNREACHABLE();
}
}
void simdjson2msgpack::recursive_processor_ref(simdjson::ondemand::value& element) {
switch (element.type()) {
case simdjson::ondemand::json_type::array: {
uint32_t counter = 0;
write_byte(0xdd);
uint8_t *location = skip_uint32();
for (auto child : element.get_array()) {
counter++;
simdjson::ondemand::value v = child.value();
recursive_processor_ref(v);
}
write_uint32_at(counter, location);
} break;
case simdjson::ondemand::json_type::object: {
uint32_t counter = 0;
write_byte(0xdf);
uint8_t *location = skip_uint32();
for (auto field : element.get_object()) {
counter++;
write_raw_string(field.key());
simdjson::ondemand::value v = field.value();
recursive_processor_ref(v);
}
write_uint32_at(counter, location);
} break;
case simdjson::ondemand::json_type::number:
write_double(element.get_double());
break;
case simdjson::ondemand::json_type::string:
write_raw_string(element.get_raw_json_string());
break;
case simdjson::ondemand::json_type::boolean:
write_byte(0xc2 + element.get_bool());
break;
case simdjson::ondemand::json_type::null:
// We check that the value is indeed null
// otherwise: an error is thrown.
if(element.is_null()) {
write_byte(0xc0);
}
break;
default:
SIMDJSON_UNREACHABLE();
@@ -180,4 +247,4 @@ BENCHMARK_TEMPLATE(json2msgpack, simdjson_ondemand)->UseManualTime();
} // namespace json2msgpack
#endif // SIMDJSON_EXCEPTIONS
#endif // SIMDJSON_EXCEPTIONS
+2 -1
View File
@@ -106,6 +106,7 @@ struct yyjson : yyjson2msgpack {
BENCHMARK_TEMPLATE(json2msgpack, yyjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
struct yyjson_insitu : yyjson2msgpack {
bool run(simdjson::padded_string &json, char *buffer,
std::string_view &result) {
@@ -116,7 +117,7 @@ struct yyjson_insitu : yyjson2msgpack {
}
};
BENCHMARK_TEMPLATE(json2msgpack, yyjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace json2msgpack
#endif // SIMDJSON_COMPETITION_YYJSON
+1 -1
View File
@@ -79,7 +79,7 @@ static const simdjson::padded_string &get_built_json_array() {
struct simdjson_dom;
template<typename I> simdjson_really_inline static void kostya(benchmark::State &state) {
template<typename I> simdjson_inline static void kostya(benchmark::State &state) {
run_json_benchmark<runner<I>, runner<simdjson_dom>>(state);
}
+9 -8
View File
@@ -13,7 +13,7 @@ struct rapidjson_base {
Document doc;
simdjson_really_inline double get_double(Value &object, std::string_view key) {
simdjson_inline double get_double(Value &object, std::string_view key) {
auto field = object.FindMember(key.data());
if (field == object.MemberEnd()) { throw "Missing double field"; }
if (!field->value.IsNumber()) { throw "Field is not double"; }
@@ -34,28 +34,29 @@ struct rapidjson_base {
return true;
}
};
struct rapidjson : rapidjson_base {
#if SIMDJSON_COMPETITION_ONDEMAND_APPROX
struct rapidjson_approx : rapidjson_base {
bool run(simdjson::padded_string &json, std::vector<point> &result) {
return rapidjson_base::run(doc.Parse<kParseValidateEncodingFlag>(json.data()), result);
}
};
BENCHMARK_TEMPLATE(kostya, rapidjson)->UseManualTime();
BENCHMARK_TEMPLATE(kostya, rapidjson_approx)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_APPROX
struct rapidjson_lossless : rapidjson_base {
struct rapidjson : rapidjson_base {
bool run(simdjson::padded_string &json, std::vector<point> &result) {
return rapidjson_base::run(doc.Parse<kParseValidateEncodingFlag | kParseFullPrecisionFlag>(json.data()), result);
}
};
BENCHMARK_TEMPLATE(kostya, rapidjson_lossless)->UseManualTime();
BENCHMARK_TEMPLATE(kostya, rapidjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
struct rapidjson_insitu : rapidjson_base {
bool run(simdjson::padded_string &json, std::vector<point> &result) {
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), result);
}
};
BENCHMARK_TEMPLATE(kostya, rapidjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace kostya
#endif // SIMDJSON_COMPETITION_RAPIDJSON
+1 -1
View File
@@ -13,7 +13,7 @@ struct sajson {
size_t *ast_buffer{nullptr};
~sajson() { free(ast_buffer); }
simdjson_really_inline double get_double(const ::sajson::value &obj, std::string_view key) {
simdjson_inline double get_double(const ::sajson::value &obj, std::string_view key) {
using namespace sajson;
auto val = obj.get_value_of_key({key.data(), key.length()});
+3 -3
View File
@@ -9,7 +9,7 @@ namespace kostya {
struct yyjson_base {
static constexpr diff_flags DiffFlags = diff_flags::NONE;
simdjson_really_inline double get_double(yyjson_val *obj, std::string_view key) {
simdjson_inline double get_double(yyjson_val *obj, std::string_view key) {
yyjson_val *val = yyjson_obj_getn(obj, key.data(), key.length());
if (!val) { throw "missing point field!"; }
if (yyjson_get_type(val) != YYJSON_TYPE_NUM) { throw "Number is not a type!"; }
@@ -53,14 +53,14 @@ struct yyjson : yyjson_base {
}
};
BENCHMARK_TEMPLATE(kostya, yyjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
struct yyjson_insitu : yyjson_base {
bool run(simdjson::padded_string &json, std::vector<point> &result) {
return yyjson_base::run(yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0), result);
}
};
BENCHMARK_TEMPLATE(kostya, yyjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace kostya
#endif // SIMDJSON_COMPETITION_YYJSON
@@ -16,11 +16,11 @@ using namespace json_benchmark;
struct brand {
double cumulative_rating;
uint64_t reviews_count;
simdjson_really_inline bool operator==(const brand &other) const {
simdjson_inline bool operator==(const brand &other) const {
return cumulative_rating == other.cumulative_rating &&
reviews_count == other.reviews_count;
}
simdjson_really_inline bool operator!=(const brand &other) const { return !(*this == other); }
simdjson_inline bool operator!=(const brand &other) const { return !(*this == other); }
};
simdjson_unused static std::ostream &operator<<(std::ostream &o, const brand &b) {
@@ -87,8 +87,8 @@ static const simdjson::padded_string &get_built_json() {
template<bool threaded>
struct simdjson_dom;
template<typename I> simdjson_really_inline static void large_amazon_cellphones(benchmark::State &state) {
template<typename I> simdjson_inline static void large_amazon_cellphones(benchmark::State &state) {
run_json_benchmark<runner<I>, runner<simdjson_dom<UNTHREADED>>>(state);
}
} // namespace large_amazon_cellphones
} // namespace large_amazon_cellphones
+9 -7
View File
@@ -13,7 +13,7 @@ struct rapidjson_base {
Document doc;
simdjson_really_inline double get_double(Value &object, std::string_view key) {
simdjson_inline double get_double(Value &object, std::string_view key) {
auto field = object.FindMember(key.data());
if (field == object.MemberEnd()) { throw "Missing double field"; }
if (!field->value.IsNumber()) { throw "Field is not double"; }
@@ -31,28 +31,30 @@ struct rapidjson_base {
return true;
}
};
struct rapidjson : rapidjson_base {
#if SIMDJSON_COMPETITION_ONDEMAND_APPROX
struct rapidjson_approx : rapidjson_base {
bool run(simdjson::padded_string &json, std::vector<point> &result) {
return rapidjson_base::run(doc.Parse<kParseValidateEncodingFlag>(json.data()), result);
}
};
BENCHMARK_TEMPLATE(large_random, rapidjson)->UseManualTime();
BENCHMARK_TEMPLATE(large_random, rapidjson_approx)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_APPROX
struct rapidjson_lossless : rapidjson_base {
struct rapidjson : rapidjson_base {
bool run(simdjson::padded_string &json, std::vector<point> &result) {
return rapidjson_base::run(doc.Parse<kParseValidateEncodingFlag | kParseFullPrecisionFlag>(json.data()), result);
}
};
BENCHMARK_TEMPLATE(large_random, rapidjson_lossless)->UseManualTime();
BENCHMARK_TEMPLATE(large_random, rapidjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
struct rapidjson_insitu : rapidjson_base {
bool run(simdjson::padded_string &json, std::vector<point> &result) {
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), result);
}
};
BENCHMARK_TEMPLATE(large_random, rapidjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace large_random
+1 -1
View File
@@ -13,7 +13,7 @@ struct sajson {
size_t *ast_buffer{nullptr};
~sajson() { free(ast_buffer); }
simdjson_really_inline double get_double(const ::sajson::value &obj, std::string_view key) {
simdjson_inline double get_double(const ::sajson::value &obj, std::string_view key) {
using namespace sajson;
auto val = obj.get_value_of_key({key.data(), key.length()});
+3 -3
View File
@@ -9,7 +9,7 @@ namespace large_random {
struct yyjson_base {
static constexpr diff_flags DiffFlags = diff_flags::NONE;
simdjson_really_inline double get_double(yyjson_val *obj, std::string_view key) {
simdjson_inline double get_double(yyjson_val *obj, std::string_view key) {
yyjson_val *val = yyjson_obj_getn(obj, key.data(), key.length());
if (!val) { throw "missing point field!"; }
if (yyjson_get_type(val) != YYJSON_TYPE_NUM) { throw "Number is not a type!"; }
@@ -51,14 +51,14 @@ struct yyjson : yyjson_base {
}
};
BENCHMARK_TEMPLATE(large_random, yyjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
struct yyjson_insitu : yyjson_base {
bool run(simdjson::padded_string &json, std::vector<point> &result) {
return yyjson_base::run(yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0), result);
}
};
BENCHMARK_TEMPLATE(large_random, yyjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace large_random
#endif // SIMDJSON_COMPETITION_YYJSON
+6 -6
View File
@@ -10,28 +10,28 @@ using namespace simdjson;
class Iter {
public:
simdjson_really_inline bool Run(const padded_string &json);
simdjson_inline bool Run(const padded_string &json);
simdjson_really_inline const std::vector<my_point> &Result() { return container; }
simdjson_really_inline size_t ItemCount() { return container.size(); }
simdjson_inline const std::vector<my_point> &Result() { return container; }
simdjson_inline size_t ItemCount() { return container.size(); }
private:
ondemand::parser parser{};
std::vector<my_point> container{};
simdjson_really_inline double first_double(ondemand::json_iterator &iter) {
simdjson_inline double first_double(ondemand::json_iterator &iter) {
if (iter.start_object().error() || iter.field_key().error() || iter.field_value()) { throw "Invalid field"; }
return iter.consume_double();
}
simdjson_really_inline double next_double(ondemand::json_iterator &iter) {
simdjson_inline double next_double(ondemand::json_iterator &iter) {
if (!iter.has_next_field() || iter.field_key().error() || iter.field_value()) { throw "Invalid field"; }
return iter.consume_double();
}
};
simdjson_really_inline bool Iter::Run(const padded_string &json) {
simdjson_inline bool Iter::Run(const padded_string &json) {
container.clear();
auto iter = parser.iterate_raw(json).value();
+4 -4
View File
@@ -10,16 +10,16 @@ using namespace simdjson;
class OnDemand {
public:
simdjson_really_inline bool Run(const padded_string &json);
simdjson_really_inline const std::vector<my_point> &Result() { return container; }
simdjson_really_inline size_t ItemCount() { return container.size(); }
simdjson_inline bool Run(const padded_string &json);
simdjson_inline const std::vector<my_point> &Result() { return container; }
simdjson_inline size_t ItemCount() { return container.size(); }
private:
ondemand::parser parser{};
std::vector<my_point> container{};
};
simdjson_really_inline bool OnDemand::Run(const padded_string &json) {
simdjson_inline bool OnDemand::Run(const padded_string &json) {
container.clear();
auto doc = parser.iterate(json);
+16 -16
View File
@@ -11,13 +11,13 @@ using namespace simdjson::builtin::stage2;
class Sax {
public:
simdjson_really_inline bool Run(const padded_string &json) noexcept;
simdjson_inline bool Run(const padded_string &json) noexcept;
simdjson_really_inline const std::vector<my_point> &Result() { return container; }
simdjson_really_inline size_t ItemCount() { return container.size(); }
simdjson_inline const std::vector<my_point> &Result() { return container; }
simdjson_inline size_t ItemCount() { return container.size(); }
private:
simdjson_really_inline error_code RunNoExcept(const padded_string &json) noexcept;
simdjson_inline error_code RunNoExcept(const padded_string &json) noexcept;
error_code Allocate(size_t new_capacity);
std::unique_ptr<uint8_t[]> string_buf{};
size_t capacity{};
@@ -34,21 +34,21 @@ public:
explicit sax_point_reader_visitor(std::vector<my_point> &_points) : points(_points) {}
simdjson_really_inline error_code visit_object_start(json_iterator &) {
simdjson_inline error_code visit_object_start(json_iterator &) {
idx = 0;
return SUCCESS;
}
simdjson_really_inline error_code visit_primitive(json_iterator &, const uint8_t *value) {
simdjson_inline error_code visit_primitive(json_iterator &, const uint8_t *value) {
if(idx == GOT_SOMETHING_ELSE) { return simdjson::SUCCESS; }
return numberparsing::parse_double(value).get(buffer[idx]);
}
simdjson_really_inline error_code visit_object_end(json_iterator &) {
simdjson_inline error_code visit_object_end(json_iterator &) {
points.emplace_back(my_point{buffer[0], buffer[1], buffer[2]});
return SUCCESS;
}
simdjson_really_inline error_code visit_document_start(json_iterator &) { return SUCCESS; }
simdjson_really_inline error_code visit_key(json_iterator &, const uint8_t * key) {
simdjson_inline error_code visit_document_start(json_iterator &) { return SUCCESS; }
simdjson_inline error_code visit_key(json_iterator &, const uint8_t * key) {
switch(key[1]) {
// Technically, we should check the other characters
// in the key, but we are cheating to go as fast
@@ -67,13 +67,13 @@ public:
}
return SUCCESS;
}
simdjson_really_inline error_code visit_array_start(json_iterator &) { return SUCCESS; }
simdjson_really_inline error_code visit_array_end(json_iterator &) { return SUCCESS; }
simdjson_really_inline error_code visit_document_end(json_iterator &) { return SUCCESS; }
simdjson_really_inline error_code visit_empty_array(json_iterator &) { return SUCCESS; }
simdjson_really_inline error_code visit_empty_object(json_iterator &) { return SUCCESS; }
simdjson_really_inline error_code visit_root_primitive(json_iterator &, const uint8_t *) { return SUCCESS; }
simdjson_really_inline error_code increment_count(json_iterator &) { return SUCCESS; }
simdjson_inline error_code visit_array_start(json_iterator &) { return SUCCESS; }
simdjson_inline error_code visit_array_end(json_iterator &) { return SUCCESS; }
simdjson_inline error_code visit_document_end(json_iterator &) { return SUCCESS; }
simdjson_inline error_code visit_empty_array(json_iterator &) { return SUCCESS; }
simdjson_inline error_code visit_empty_object(json_iterator &) { return SUCCESS; }
simdjson_inline error_code visit_root_primitive(json_iterator &, const uint8_t *) { return SUCCESS; }
simdjson_inline error_code increment_count(json_iterator &) { return SUCCESS; }
};
// NOTE: this assumes the dom_parser is already allocated
+19 -34
View File
@@ -1,22 +1,13 @@
// https://github.com/WojciechMula/toys/blob/master/000helpers/linux-perf-events.h
#pragma once
#ifdef __linux__
#ifdef __has_include
#if __has_include(<asm/unistd.h>)
#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 <sys/ioctl.h> // for ioctl
#include <unistd.h> // for syscall
#include <cerrno> // for errno
#include <cstring> // for std::memset
#include <cstring> // for memset
#include <stdexcept>
#include <iostream>
@@ -28,13 +19,11 @@ template <int TYPE = PERF_TYPE_HARDWARE> class LinuxEvents {
perf_event_attr attribs{};
size_t num_events{};
std::vector<uint64_t> temp_result_vec{};
std::vector<uint64_t> result{};
std::vector<int> fds{};
bool quiet;
std::vector<uint64_t> ids{};
public:
explicit LinuxEvents(std::vector<int> config_vec, bool _quiet=false) : fd(0), working(true), quiet{_quiet} {
std::memset(&attribs, 0, sizeof(attribs));
explicit LinuxEvents(std::vector<int> config_vec) : fd(0), working(true) {
memset(&attribs, 0, sizeof(attribs));
attribs.type = TYPE;
attribs.size = sizeof(attribs);
attribs.disabled = 1;
@@ -49,7 +38,7 @@ public:
int group = -1; // no group
num_events = config_vec.size();
result.resize(config_vec.size());
ids.resize(config_vec.size());
uint32_t i = 0;
for (auto config : config_vec) {
attribs.config = config;
@@ -57,22 +46,17 @@ public:
if (_fd == -1) {
report_error("perf_event_open");
}
fd = _fd; // fd tracks the last _fd value.
fds.push_back(fd);
ioctl(fd, PERF_EVENT_IOC_ID, &result[i++]);
ioctl(_fd, PERF_EVENT_IOC_ID, &ids[i++]);
if (group == -1) {
group = fd;
group = _fd;
fd = _fd;
}
}
temp_result_vec.resize(num_events * 2 + 1);
}
~LinuxEvents() {
for (auto tfd : fds) {
if (tfd != -1) { close(tfd); }
}
}
~LinuxEvents() { if (fd != -1) { close(fd); } }
inline void start() {
if (fd != -1) {
@@ -97,10 +81,16 @@ public:
}
}
// 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) {
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() {
@@ -108,13 +98,8 @@ public:
}
private:
void report_error(const std::string &context) {
if (!quiet) {
if (working) {
std::cerr << (context + ": " + std::string(strerror(errno))) << std::endl;
}
}
void report_error(const std::string &) {
working = false;
}
};
#endif
#endif
+2 -2
View File
@@ -9,7 +9,7 @@ namespace partial_tweets {
struct nlohmann_json {
using StringType=std::string;
simdjson_really_inline uint64_t nullable_int(nlohmann::json value) {
simdjson_inline uint64_t nullable_int(nlohmann::json value) {
if (value.is_null()) { return 0; }
return value;
}
@@ -37,4 +37,4 @@ BENCHMARK_TEMPLATE(partial_tweets, nlohmann_json)->UseManualTime();
} // namespace partial_tweets
#endif // SIMDJSON_COMPETITION_NLOHMANN_JSON
#endif // SIMDJSON_COMPETITION_NLOHMANN_JSON
+6 -6
View File
@@ -17,27 +17,27 @@ public:
displayed_implementation = true;
}
}
simdjson_really_inline bool Run(const padded_string &json);
simdjson_really_inline const std::vector<tweet> &Result() { return tweets; }
simdjson_really_inline size_t ItemCount() { return tweets.size(); }
simdjson_inline bool Run(const padded_string &json);
simdjson_inline const std::vector<tweet> &Result() { return tweets; }
simdjson_inline size_t ItemCount() { return tweets.size(); }
private:
ondemand::parser parser{};
std::vector<tweet> tweets{};
simdjson_really_inline uint64_t nullable_int(ondemand::value value) {
simdjson_inline uint64_t nullable_int(ondemand::value value) {
if (value.is_null()) { return 0; }
return value;
}
simdjson_really_inline twitter_user read_user(ondemand::object user) {
simdjson_inline twitter_user read_user(ondemand::object user) {
return { user.find_field("id"), user.find_field("screen_name") };
}
static inline bool displayed_implementation = false;
};
simdjson_really_inline bool OnDemand::Run(const padded_string &json) {
simdjson_inline bool OnDemand::Run(const padded_string &json) {
tweets.clear();
// Walk the document, parsing the tweets as we go
+1 -1
View File
@@ -39,7 +39,7 @@ struct runner : public file_runner<I> {
struct simdjson_dom;
template<typename I> simdjson_really_inline static void partial_tweets(benchmark::State &state) {
template<typename I> simdjson_inline static void partial_tweets(benchmark::State &state) {
run_json_benchmark<runner<I>, runner<simdjson_dom>>(state);
}
+6 -6
View File
@@ -13,27 +13,27 @@ struct rapidjson_base {
Document doc{};
simdjson_really_inline std::string_view get_string_view(Value &object, std::string_view key) {
simdjson_inline std::string_view get_string_view(Value &object, std::string_view key) {
// TODO use version that supports passing string length?
auto field = object.FindMember(key.data());
if (field == object.MemberEnd()) { throw "Missing object field"; }
if (!field->value.IsString()) { throw "Field is not a string"; }
return { field->value.GetString(), field->value.GetStringLength() };
}
simdjson_really_inline uint64_t get_uint64(Value &object, std::string_view key) {
simdjson_inline uint64_t get_uint64(Value &object, std::string_view key) {
auto field = object.FindMember(key.data());
if (field == object.MemberEnd()) { throw "Missing object field"; }
if (!field->value.IsUint64()) { throw "Field is not uint64"; }
return field->value.GetUint64();
}
simdjson_really_inline uint64_t get_nullable_uint64(Value &object, std::string_view key) {
simdjson_inline uint64_t get_nullable_uint64(Value &object, std::string_view key) {
auto field = object.FindMember(key.data());
if (field == object.MemberEnd()) { throw "Missing nullable uint64 field"; }
if (field->value.IsNull()) { return 0; }
if (!field->value.IsUint64()) { throw "Field is not nullable uint64"; }
return field->value.GetUint64();
}
simdjson_really_inline partial_tweets::twitter_user<std::string_view> get_user(Value &object, std::string_view key) {
simdjson_inline partial_tweets::twitter_user<std::string_view> get_user(Value &object, std::string_view key) {
auto field = object.FindMember(key.data());
if (field == object.MemberEnd()) { throw "Missing user field"; }
if (!field->value.IsObject()) { throw "User field is not an object"; }
@@ -67,14 +67,14 @@ struct rapidjson : rapidjson_base {
}
};
BENCHMARK_TEMPLATE(partial_tweets, rapidjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
struct rapidjson_insitu : rapidjson_base {
bool run(simdjson::padded_string &json, std::vector<tweet<std::string_view>> &result) {
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), result);
}
};
BENCHMARK_TEMPLATE(partial_tweets, rapidjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace partial_tweets
#endif // SIMDJSON_COMPETITION_RAPIDJSON
+5 -5
View File
@@ -13,12 +13,12 @@ struct sajson {
size_t *ast_buffer{nullptr};
~sajson() { free(ast_buffer); }
simdjson_really_inline std::string_view get_string_view(const ::sajson::value &obj, std::string_view key) {
simdjson_inline std::string_view get_string_view(const ::sajson::value &obj, std::string_view key) {
auto val = obj.get_value_of_key({key.data(), key.length()});
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field is not a string"; }
return { val.as_cstring(), val.get_string_length() };
}
simdjson_really_inline uint64_t get_uint52(const ::sajson::value &obj, std::string_view key) {
simdjson_inline uint64_t get_uint52(const ::sajson::value &obj, std::string_view key) {
auto val = obj.get_value_of_key({key.data(), key.length()});
switch (val.get_type()) {
case ::sajson::TYPE_INTEGER: {
@@ -30,7 +30,7 @@ struct sajson {
throw "field not integer";
}
}
simdjson_really_inline uint64_t get_str_uint64(const ::sajson::value &obj, std::string_view key) {
simdjson_inline uint64_t get_str_uint64(const ::sajson::value &obj, std::string_view key) {
// Since sajson only supports 53-bit numbers, and IDs in twitter.json can be > 53 bits, we read the corresponding id_str and parse that.
auto val = obj.get_value_of_key({key.data(), key.length()});
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field not a string"; }
@@ -40,7 +40,7 @@ struct sajson {
if (endptr != &str[val.get_string_length()]) { throw "field is a string, but not an integer string"; }
return result;
}
simdjson_really_inline uint64_t get_nullable_str_uint64(const ::sajson::value &obj, std::string_view key) {
simdjson_inline uint64_t get_nullable_str_uint64(const ::sajson::value &obj, std::string_view key) {
auto val = obj.get_value_of_key({key.data(), key.length()});
if (val.get_type() == ::sajson::TYPE_NULL) { return 0; }
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field not a string"; }
@@ -50,7 +50,7 @@ struct sajson {
if (endptr != &str[val.get_string_length()]) { throw "field is a string, but not an integer string"; }
return result;
}
simdjson_really_inline partial_tweets::twitter_user<std::string_view> get_user(const ::sajson::value &obj, std::string_view key) {
simdjson_inline partial_tweets::twitter_user<std::string_view> get_user(const ::sajson::value &obj, std::string_view key) {
auto user = obj.get_value_of_key({key.data(), key.length()});
if (user.get_type() != ::sajson::TYPE_OBJECT) { throw "user is not an object"; }
return { get_str_uint64(user, "id_str"), get_string_view(user, "screen_name") };
+2 -2
View File
@@ -13,7 +13,7 @@ struct simdjson_dom {
dom::parser parser{};
simdjson_really_inline uint64_t nullable_int(dom::element element) {
simdjson_inline uint64_t nullable_int(dom::element element) {
if (element.is_null()) { return 0; }
return element;
}
@@ -40,4 +40,4 @@ BENCHMARK_TEMPLATE(partial_tweets, simdjson_dom)->UseManualTime();
} // namespace partial_tweets
#endif // SIMDJSON_EXCEPTIONS
#endif // SIMDJSON_EXCEPTIONS
+2 -2
View File
@@ -13,12 +13,12 @@ struct simdjson_ondemand {
ondemand::parser parser{};
simdjson_really_inline uint64_t nullable_int(ondemand::value value) {
simdjson_inline uint64_t nullable_int(ondemand::value value) {
if (value.is_null()) { return 0; }
return value;
}
simdjson_really_inline twitter_user<std::string_view> read_user(ondemand::object user) {
simdjson_inline twitter_user<std::string_view> read_user(ondemand::object user) {
return { user.find_field("id"), user.find_field("screen_name") };
}
+2 -2
View File
@@ -32,7 +32,7 @@ struct tweet {
uint64_t retweet_count{};
uint64_t favorite_count{};
template<typename OtherStringType>
simdjson_really_inline bool operator==(const tweet<OtherStringType> &other) const {
simdjson_inline bool operator==(const tweet<OtherStringType> &other) const {
return created_at == other.created_at &&
id == other.id &&
result == other.result &&
@@ -42,7 +42,7 @@ struct tweet {
favorite_count == other.favorite_count;
}
template<typename OtherStringType>
simdjson_really_inline bool operator!=(const tweet<OtherStringType> &other) const { return !(*this == other); }
simdjson_inline bool operator!=(const tweet<OtherStringType> &other) const { return !(*this == other); }
};
template<typename StringType>
+6 -6
View File
@@ -9,24 +9,24 @@ namespace partial_tweets {
struct yyjson_base {
using StringType=std::string_view;
simdjson_really_inline std::string_view get_string_view(yyjson_val *obj, std::string_view key) {
simdjson_inline std::string_view get_string_view(yyjson_val *obj, std::string_view key) {
auto val = yyjson_obj_getn(obj, key.data(), key.length());
if (!yyjson_is_str(val)) { throw "field is not uint64 or null!"; }
return { yyjson_get_str(val), yyjson_get_len(val) };
}
simdjson_really_inline uint64_t get_uint64(yyjson_val *obj, std::string_view key) {
simdjson_inline uint64_t get_uint64(yyjson_val *obj, std::string_view key) {
auto val = yyjson_obj_getn(obj, key.data(), key.length());
if (!yyjson_is_uint(val)) { throw "field is not uint64 or null!"; }
return yyjson_get_uint(val);
}
simdjson_really_inline uint64_t get_nullable_uint64(yyjson_val *obj, std::string_view key) {
simdjson_inline uint64_t get_nullable_uint64(yyjson_val *obj, std::string_view key) {
auto val = yyjson_obj_getn(obj, key.data(), key.length());
if (!yyjson_is_uint(val)) { }
auto type = yyjson_get_type(val);
if (type != YYJSON_TYPE_NUM && type != YYJSON_TYPE_NULL ) { throw "field is not uint64 or null!"; }
return yyjson_get_uint(val);
}
simdjson_really_inline partial_tweets::twitter_user<std::string_view> get_user(yyjson_val *obj, std::string_view key) {
simdjson_inline partial_tweets::twitter_user<std::string_view> get_user(yyjson_val *obj, std::string_view key) {
auto user = yyjson_obj_getn(obj, key.data(), key.length());
if (!yyjson_is_obj(user)) { throw "missing twitter user field!"; }
return { get_uint64(user, "id"), get_string_view(user, "screen_name") };
@@ -66,14 +66,14 @@ struct yyjson : yyjson_base {
}
};
BENCHMARK_TEMPLATE(partial_tweets, yyjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
struct yyjson_insitu : yyjson_base {
bool run(simdjson::padded_string &json, std::vector<tweet<std::string_view>> &result) {
return yyjson_base::run(yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0), result);
}
};
BENCHMARK_TEMPLATE(partial_tweets, yyjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace partial_tweets
#endif // SIMDJSON_COMPETITION_YYJSON
+2 -2
View File
@@ -56,14 +56,14 @@ struct rapidjson : rapidjson_base {
}
};
BENCHMARK_TEMPLATE(top_tweet, rapidjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
struct rapidjson_insitu : rapidjson_base {
bool run(simdjson::padded_string &json, int64_t max_retweet_count, top_tweet_result<StringType> &result) {
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), max_retweet_count, result);
}
};
BENCHMARK_TEMPLATE(top_tweet, rapidjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace top_tweet
#endif // SIMDJSON_COMPETITION_RAPIDJSON
+3 -3
View File
@@ -13,13 +13,13 @@ struct top_tweet_result {
StringType screen_name{};
StringType text{};
template<typename OtherStringType>
simdjson_really_inline bool operator==(const top_tweet_result<OtherStringType> &other) const {
simdjson_inline bool operator==(const top_tweet_result<OtherStringType> &other) const {
return retweet_count == other.retweet_count &&
screen_name == other.screen_name &&
text == other.text;
}
template<typename OtherStringType>
simdjson_really_inline bool operator!=(const top_tweet_result<OtherStringType> &other) const { return !(*this == other); }
simdjson_inline bool operator!=(const top_tweet_result<OtherStringType> &other) const { return !(*this == other); }
};
template<typename StringType>
@@ -60,7 +60,7 @@ struct runner : public file_runner<I> {
struct simdjson_dom;
template<typename I> simdjson_really_inline static void top_tweet(benchmark::State &state) {
template<typename I> simdjson_inline static void top_tweet(benchmark::State &state) {
json_benchmark::run_json_benchmark<runner<I>, runner<simdjson_dom>>(state);
}
+2 -2
View File
@@ -55,14 +55,14 @@ struct yyjson : yyjson_base {
}
};
BENCHMARK_TEMPLATE(top_tweet, yyjson)->UseManualTime();
#if SIMDJSON_COMPETITION_ONDEMAND_INSITU
struct yyjson_insitu : yyjson_base {
bool run(simdjson::padded_string &json, int64_t max_retweet_count, top_tweet_result<StringType> &result) {
return yyjson_base::run(yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0), max_retweet_count, result);
}
};
BENCHMARK_TEMPLATE(top_tweet, yyjson_insitu)->UseManualTime();
#endif // SIMDJSON_COMPETITION_ONDEMAND_INSITU
} // namespace top_tweet
#endif // SIMDJSON_COMPETITION_YYJSON
+23
View File
@@ -0,0 +1,23 @@
# This module provides function for joining paths
# known from most languages
#
# SPDX-License-Identifier: (MIT OR CC0-1.0)
# Copyright 2020 Jan Tojnar
# https://github.com/jtojnar/cmake-snips
#
# Modelled after Pythons os.path.join
# https://docs.python.org/3.7/library/os.path.html#os.path.join
# Windows not supported
function(join_paths joined_path first_path_segment)
set(temp_path "${first_path_segment}")
foreach(current_segment IN LISTS ARGN)
if(NOT ("${current_segment}" STREQUAL ""))
if(IS_ABSOLUTE "${current_segment}")
set(temp_path "${current_segment}")
else()
set(temp_path "${temp_path}/${current_segment}")
endif()
endif()
endforeach()
set(${joined_path} "${temp_path}" PARENT_SCOPE)
endfunction()
+38 -1
View File
@@ -50,6 +50,23 @@ undefined behavior.")
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)
message(STATUS "Setting both the thread 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)
message(STATUS "No build type selected and you have enabled the sanitizer, \
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)
else()
message(STATUS "No build type selected, default to Release")
@@ -91,7 +110,8 @@ endif()
# We compile tools, tests, etc. with C++ 17. Override yourself if you need on a
# 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_EXTENSIONS OFF)
set(CMAKE_MACOSX_RPATH OFF)
@@ -144,6 +164,11 @@ else()
)
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
#
@@ -187,6 +212,18 @@ else()
message(STATUS "AVX-512 instructions are not allowed.")
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)
check_symbol_exists(fork unistd.h HAVE_POSIX_FORK)
check_symbol_exists(wait sys/wait.h HAVE_POSIX_WAIT)
+13 -5
View File
@@ -15,7 +15,7 @@ if(SIMDJSON_GOOGLE_BENCHMARKS)
set_off(BENCHMARK_ENABLE_INSTALL)
set_off(BENCHMARK_ENABLE_WERROR)
import_dependency(google_benchmarks google/benchmark f91b6b4)
import_dependency(google_benchmarks google/benchmark v1.7.1)
add_dependency(google_benchmarks)
endif()
@@ -70,11 +70,11 @@ int main() {}
target_include_directories(jsmn SYSTEM PUBLIC "${jsmn_SOURCE_DIR}")
target_compile_definitions(jsmn INTERFACE SIMDJSON_COMPETITION_JSMN)
message(STATUS "Importing json (nlohmann/json@v3.9.1)")
message(STATUS "Importing json (nlohmann/json@v3.10.5)")
set(nlohmann_json_SOURCE_DIR "${dep_root}/json")
if(NOT EXISTS "${nlohmann_json_SOURCE_DIR}")
file(DOWNLOAD
"https://github.com/nlohmann/json/releases/download/v3.9.1/json.hpp"
"https://github.com/nlohmann/json/releases/download/v3.10.5/json.hpp"
"${nlohmann_json_SOURCE_DIR}/nlohmann/json.hpp")
endif()
add_library(nlohmann_json INTERFACE)
@@ -91,9 +91,17 @@ int main() {}
target_include_directories(jsoncpp SYSTEM PUBLIC "${jsoncpp_SOURCE_DIR}")
target_compile_definitions(jsoncpp INTERFACE SIMDJSON_COMPETITION_JSONCPP)
import_dependency(rapidjson Tencent/rapidjson b32cd94)
import_dependency(rapidjson Tencent/rapidjson f54b0e4)
add_library(rapidjson INTERFACE)
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
"${rapidjson_SOURCE_DIR}/include")
target_compile_definitions(rapidjson INTERFACE SIMDJSON_COMPETITION_RAPIDJSON)
@@ -114,7 +122,7 @@ int main() {}
"${ujson4c_SOURCE_DIR}/3rdparty")
target_compile_definitions(ujson4c INTERFACE SIMDJSON_COMPETITION_UJSON4C)
import_dependency(yyjson ibireme/yyjson aa33ec5)
import_dependency(yyjson ibireme/yyjson c385651)
add_library(yyjson STATIC "${yyjson_SOURCE_DIR}/src/yyjson.c")
target_include_directories(yyjson SYSTEM PUBLIC "${yyjson_SOURCE_DIR}/src")
target_compile_definitions(yyjson INTERFACE SIMDJSON_COMPETITION_YYJSON)
+1 -1
View File
@@ -40,7 +40,7 @@ macro(add_dependency NAME)
message(FATAL_ERROR "Missing ${NAME}_SOURCE_DIR variable")
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()
function(set_off NAME)
+192 -90
View File
@@ -79,6 +79,150 @@ license you like.
/// to prevent private header inclusion.
#define JSON_IS_AMALGAMATION
// //////////////////////////////////////////////////////////////////////
// Beginning of content of file: include/json/version.h
// //////////////////////////////////////////////////////////////////////
#ifndef JSON_VERSION_H_INCLUDED
#define JSON_VERSION_H_INCLUDED
// Note: version must be updated in three places when doing a release. This
// annoying process ensures that amalgamate, CMake, and meson all report the
// correct version.
// 1. /meson.build
// 2. /include/json/version.h
// 3. /CMakeLists.txt
// IMPORTANT: also update the SOVERSION!!
#define JSONCPP_VERSION_STRING "1.9.5"
#define JSONCPP_VERSION_MAJOR 1
#define JSONCPP_VERSION_MINOR 9
#define JSONCPP_VERSION_PATCH 5
#define JSONCPP_VERSION_QUALIFIER
#define JSONCPP_VERSION_HEXA \
((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \
(JSONCPP_VERSION_PATCH << 8))
#ifdef JSONCPP_USING_SECURE_MEMORY
#undef JSONCPP_USING_SECURE_MEMORY
#endif
#define JSONCPP_USING_SECURE_MEMORY 0
// If non-zero, the library zeroes any memory that it has allocated before
// it frees its memory.
#endif // JSON_VERSION_H_INCLUDED
// //////////////////////////////////////////////////////////////////////
// End of content of file: include/json/version.h
// //////////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////
// Beginning of content of file: include/json/allocator.h
// //////////////////////////////////////////////////////////////////////
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef JSON_ALLOCATOR_H_INCLUDED
#define JSON_ALLOCATOR_H_INCLUDED
#include <cstring>
#include <memory>
#pragma pack(push, 8)
namespace Json {
template <typename T> class SecureAllocator {
public:
// Type definitions
using value_type = T;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
/**
* Allocate memory for N items using the standard allocator.
*/
pointer allocate(size_type n) {
// allocate using "global operator new"
return static_cast<pointer>(::operator new(n * sizeof(T)));
}
/**
* Release memory which was allocated for N items at pointer P.
*
* The memory block is filled with zeroes before being released.
*/
void deallocate(pointer p, size_type n) {
// memset_s is used because memset may be optimized away by the compiler
memset_s(p, n * sizeof(T), 0, n * sizeof(T));
// free using "global operator delete"
::operator delete(p);
}
/**
* Construct an item in-place at pointer P.
*/
template <typename... Args> void construct(pointer p, Args&&... args) {
// construct using "placement new" and "perfect forwarding"
::new (static_cast<void*>(p)) T(std::forward<Args>(args)...);
}
size_type max_size() const { return size_t(-1) / sizeof(T); }
pointer address(reference x) const { return std::addressof(x); }
const_pointer address(const_reference x) const { return std::addressof(x); }
/**
* Destroy an item in-place at pointer P.
*/
void destroy(pointer p) {
// destroy using "explicit destructor"
p->~T();
}
// Boilerplate
SecureAllocator() {}
template <typename U> SecureAllocator(const SecureAllocator<U>&) {}
template <typename U> struct rebind { using other = SecureAllocator<U>; };
};
template <typename T, typename U>
bool operator==(const SecureAllocator<T>&, const SecureAllocator<U>&) {
return true;
}
template <typename T, typename U>
bool operator!=(const SecureAllocator<T>&, const SecureAllocator<U>&) {
return false;
}
} // namespace Json
#pragma pack(pop)
#endif // JSON_ALLOCATOR_H_INCLUDED
// //////////////////////////////////////////////////////////////////////
// End of content of file: include/json/allocator.h
// //////////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////
// Beginning of content of file: include/json/config.h
// //////////////////////////////////////////////////////////////////////
@@ -99,47 +243,38 @@ license you like.
#include <string>
#include <type_traits>
/// If defined, indicates that json library is embedded in CppTL library.
//# define JSON_IN_CPPTL 1
/// If defined, indicates that json may leverage CppTL library
//# define JSON_USE_CPPTL 1
/// If defined, indicates that cpptl vector based map should be used instead of
/// std::map
/// as Value container.
//# define JSON_USE_CPPTL_SMALLMAP 1
// If non-zero, the library uses exceptions to report bad input instead of C
// assertion macros. The default is to use exceptions.
#ifndef JSON_USE_EXCEPTION
#define JSON_USE_EXCEPTION 1
#endif
// Temporary, tracked for removal with issue #982.
#ifndef JSON_USE_NULLREF
#define JSON_USE_NULLREF 1
#endif
/// If defined, indicates that the source file is amalgamated
/// to prevent private header inclusion.
/// Remarks: it is automatically defined in the generated amalgamated header.
// #define JSON_IS_AMALGAMATION
#ifdef JSON_IN_CPPTL
#include <cpptl/config.h>
#ifndef JSON_USE_CPPTL
#define JSON_USE_CPPTL 1
#endif
#endif
#ifdef JSON_IN_CPPTL
#define JSON_API CPPTL_API
#elif defined(JSON_DLL_BUILD)
// Export macros for DLL visibility
#if defined(JSON_DLL_BUILD)
#if defined(_MSC_VER) || defined(__MINGW32__)
#define JSON_API __declspec(dllexport)
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
#elif defined(__GNUC__) || defined(__clang__)
#define JSON_API __attribute__((visibility("default")))
#endif // if defined(_MSC_VER)
#elif defined(JSON_DLL)
#if defined(_MSC_VER) || defined(__MINGW32__)
#define JSON_API __declspec(dllimport)
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
#endif // if defined(_MSC_VER)
#endif // ifdef JSON_IN_CPPTL
#endif // ifdef JSON_DLL_BUILD
#if !defined(JSON_API)
#define JSON_API
#endif
@@ -152,8 +287,8 @@ license you like.
#if defined(_MSC_VER) && _MSC_VER < 1900
// As recommended at
// https://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010
extern JSON_API int
msvc_pre1900_c99_snprintf(char* outBuf, size_t size, const char* format, ...);
extern JSON_API int msvc_pre1900_c99_snprintf(char* outBuf, size_t size,
const char* format, ...);
#define jsoncpp_snprintf msvc_pre1900_c99_snprintf
#else
#define jsoncpp_snprintf std::snprintf
@@ -164,69 +299,30 @@ msvc_pre1900_c99_snprintf(char* outBuf, size_t size, const char* format, ...);
// Storages, and 64 bits integer support is disabled.
// #define JSON_NO_INT64 1
#if defined(_MSC_VER) // MSVC
#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
#endif // defined(_MSC_VER)
// JSONCPP_OVERRIDE is maintained for backwards compatibility of external tools.
// C++11 should be used directly in JSONCPP.
#define JSONCPP_OVERRIDE override
#if __cplusplus >= 201103L
#define JSONCPP_NOEXCEPT noexcept
#define JSONCPP_OP_EXPLICIT explicit
#elif defined(_MSC_VER) && _MSC_VER < 1900
#define JSONCPP_NOEXCEPT throw()
#define JSONCPP_OP_EXPLICIT explicit
#elif defined(_MSC_VER) && _MSC_VER >= 1900
#define JSONCPP_NOEXCEPT noexcept
#define JSONCPP_OP_EXPLICIT explicit
#else
#define JSONCPP_NOEXCEPT throw()
#define JSONCPP_OP_EXPLICIT
#endif
#ifndef JSON_HAS_RVALUE_REFERENCES
#if defined(_MSC_VER)
#define JSON_HAS_RVALUE_REFERENCES 1
#endif // MSVC >= 2013
#ifdef __clang__
#if __has_feature(cxx_rvalue_references)
#define JSON_HAS_RVALUE_REFERENCES 1
#endif // has_feature
#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc)
#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L)
#define JSON_HAS_RVALUE_REFERENCES 1
#endif // GXX_EXPERIMENTAL
#endif // __clang__ || __GNUC__
#endif // not defined JSON_HAS_RVALUE_REFERENCES
#ifndef JSON_HAS_RVALUE_REFERENCES
#define JSON_HAS_RVALUE_REFERENCES 0
#endif
#ifdef __clang__
#if __has_extension(attribute_deprecated_with_message)
#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
#endif
#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc)
#elif defined(__GNUC__) // not clang (gcc comes later since clang emulates gcc)
#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__))
#endif // GNUC version
#endif // __clang__ || __GNUC__
#endif // GNUC version
#elif defined(_MSC_VER) // MSVC (after clang because clang on Windows emulates
// MSVC)
#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
#endif // __clang__ || __GNUC__ || _MSC_VER
#if !defined(JSONCPP_DEPRECATED)
#define JSONCPP_DEPRECATED(message)
#endif // if !defined(JSONCPP_DEPRECATED)
#if __GNUC__ >= 6
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 6))
#define JSON_USE_INT64_DOUBLE_CONVERSION 1
#endif
@@ -238,37 +334,37 @@ msvc_pre1900_c99_snprintf(char* outBuf, size_t size, const char* format, ...);
#endif // if !defined(JSON_IS_AMALGAMATION)
namespace Json {
typedef int Int;
typedef unsigned int UInt;
using Int = int;
using UInt = unsigned int;
#if defined(JSON_NO_INT64)
typedef int LargestInt;
typedef unsigned int LargestUInt;
using LargestInt = int;
using LargestUInt = unsigned int;
#undef JSON_HAS_INT64
#else // if defined(JSON_NO_INT64)
// For Microsoft Visual use specific types as long long is not supported
#if defined(_MSC_VER) // Microsoft Visual Studio
typedef __int64 Int64;
typedef unsigned __int64 UInt64;
using Int64 = __int64;
using UInt64 = unsigned __int64;
#else // if defined(_MSC_VER) // Other platforms, use long long
typedef int64_t Int64;
typedef uint64_t UInt64;
using Int64 = int64_t;
using UInt64 = uint64_t;
#endif // if defined(_MSC_VER)
typedef Int64 LargestInt;
typedef UInt64 LargestUInt;
using LargestInt = Int64;
using LargestUInt = UInt64;
#define JSON_HAS_INT64
#endif // if defined(JSON_NO_INT64)
template <typename T>
using Allocator = typename std::conditional<JSONCPP_USING_SECURE_MEMORY,
SecureAllocator<T>,
std::allocator<T>>::type;
using Allocator =
typename std::conditional<JSONCPP_USING_SECURE_MEMORY, SecureAllocator<T>,
std::allocator<T>>::type;
using String = std::basic_string<char, std::char_traits<char>, Allocator<char>>;
using IStringStream = std::basic_istringstream<String::value_type,
String::traits_type,
String::allocator_type>;
using OStringStream = std::basic_ostringstream<String::value_type,
String::traits_type,
String::allocator_type>;
using IStringStream =
std::basic_istringstream<String::value_type, String::traits_type,
String::allocator_type>;
using OStringStream =
std::basic_ostringstream<String::value_type, String::traits_type,
String::allocator_type>;
using IStream = std::istream;
using OStream = std::ostream;
} // namespace Json
@@ -310,17 +406,23 @@ using JSONCPP_OSTREAM = Json::OStream;
namespace Json {
// writer.h
class StreamWriter;
class StreamWriterBuilder;
class Writer;
class FastWriter;
class StyledWriter;
class StyledStreamWriter;
// reader.h
class Reader;
class CharReader;
class CharReaderBuilder;
// features.h
// json_features.h
class Features;
// value.h
typedef unsigned int ArrayIndex;
using ArrayIndex = unsigned int;
class StaticString;
class Path;
class PathArgument;
+541 -561
View File
File diff suppressed because it is too large Load Diff
+508 -604
View File
File diff suppressed because it is too large Load Diff
+517 -81
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)
- [Documents are Iterators](#documents-are-iterators)
- [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: Additional examples](#using-the-parsed-json-additional-examples)
- [Minifying JSON strings without parsing](#minifying-json-strings-without-parsing)
@@ -23,25 +23,30 @@ An overview of what you need to know to use simdjson, with examples.
- [Disabling Exceptions](#disabling-exceptions)
- [Exceptions](#exceptions)
- [Current location in document](#current-location-in-document)
- [Checking for trailing content](#checking-for-trailing-content)
- [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)
- [Parsing Numbers Inside Strings](#parsing-numbers-inside-strings)
- [Dynamic Number Types](#dynamic-number-types)
- [Raw Strings](#raw-strings)
- [General Direct Access to the Raw JSON String](#general-direct-access-to-the-raw-json-string)
- [Thread Safety](#thread-safety)
- [Standard Compliance](#standard-compliance)
- [Backwards Compatibility](#backwards-compatibility)
- [Examples](#examples)
- [Performance Tips](#performance-tips)
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.
- 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).
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.
We test the library on a big-endian system (IBM s390x with Linux) .
Including simdjson
------------------
@@ -61,7 +66,7 @@ c++ myproject.cpp simdjson.cpp
```
Note:
- Users on macOS and other platforms where default compilers do not provide C++11 compliant by default should request it with the appropriate flag (e.g., `c++ -std=c++17 myproject.cpp simdjson.cpp`).
- Users on macOS and other platforms where default compilers do not provide C++11 compliant by default should request it with the appropriate flag (e.g., `c++ -std=c++11 myproject.cpp simdjson.cpp`).
- The library relies on [runtime CPU detection](implementation-selection.md): avoid specifying an architecture at compile time (e.g., `-march-native`).
Using simdjson with package managers
@@ -99,7 +104,7 @@ We recommend CMake version 3.15 or better.
See [our CMake demonstration](https://github.com/simdjson/cmake_demo_single_file). It works under Linux, FreeBSD, macOS and Windows (including Visual Studio).
The CMake build in simdjson can be taylored with a few variables. You can see the available variables and their default values by entering the `cmake -LA` command.
The CMake build in simdjson can be tailored with a few variables. You can see the available variables and their default values by entering the `cmake -LA` command.
Versions
@@ -140,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
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
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
@@ -151,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
```
You can also create a padded string---for efficiency reasons, simdjson requires a string
with a few bytes (`simdjson::SIMDJSON_PADDING`) at the end---and calling `iterate()`:
You can also create a padded string---and call `iterate()`:
```c++
ondemand::parser parser;
@@ -172,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 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.
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.
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
-----------------------
@@ -206,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
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).
@@ -245,27 +279,34 @@ transcode the UTF-8 strings produced by the simdjson library to other formats. S
Using the Parsed JSON
---------------------
We recommend that you first compile and run your code in Debug mode (with `NDEBUG`
undefined). When you do so, the simdjson library runs additional sanity tests on
your code to help ensure that you are using the library in a safe manner. Once
your code has been tested, you can then run it in Release mode (with `NDEBUG`
defined) for best performance. Alternatively, you can set the macro
`SIMDJSON_DEVELOPMENT_CHECKS` to 1 prior to including the `simdjson.h` header
to enable these additional checks: just make sure you remove the definition once your
code has been tested.
We recommend that you first compile and run your code in Debug mode: under Visual Studio,
it means having the `_DEBUG` macro defined, and, for other compilers, it means leaving
the `__OPTIMIZE__` macro undefined. The simdjson code will set `SIMDJSON_DEVELOPMENT_CHECKS=1`.
Alternatively, you can set the macro `SIMDJSON_DEVELOPMENT_CHECKS` to 1 prior to including
the `simdjson.h` header to enable these additional checks: just make sure you remove the
definition once your code has been tested. When `SIMDJSON_DEVELOPMENT_CHECKS` is set to 1, the
simdjson library runs additional (expensive) tests on your code to help ensure that you are
using the library in a safe manner. Once your code has been tested, you can then run it in
Release mode: under Visual Studio, it means having the `_DEBUG` macro undefined, and, for other
compilers, it means setting `__OPTIMIZE__` to a positive integer. You can also forcefully
disable these checks by setting `SIMDJSON_DEVELOPMENT_CHECKS` to 0. 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.
Once you have a document (`simdjson::ondemand::document`), you can navigate it with
idiomatic C++ iterators, operators and casts. Besides the document instances and
native types (`double`, `uint64_t`, `int64_t`, `bool`), we also access
Unicode (UTF-8) strings (`std::string_view`), objects (`simdjson::ondemand::object`)
and arrays (`simdjson::ondemand::array`).
We also have a generic type (`simdjson::ondemand::value`) which represents a potential
We also have a generic ephemeral type (`simdjson::ondemand::value`) which represents a potential
array or object, or scalar type (`double`, `uint64_t`, `int64_t`, `bool`, `null`, string) inside
an array or an object. Both generic types (`simdjson::ondemand::document` and
`simdjson::ondemand::value`) have a `type()` method returning a `json_type` value describing the
value (`json_type::array`, `json_type::object`, `json_type::number`, `json_type::string`, `json_type::boolean`, `json_type::null`).
value (`json_type::array`, `json_type::object`, `json_type::number`, `json_type::string`,
`json_type::boolean`, `json_type::null`). A generic value (`simdjson::ondemand::value`)
is only valid temporarily, as soon as you access other values, other keys in objects, etc.
it becomes invalid: you should therefore consume the value immediately by converting it to a
scalar type, an array or an object.
Advanced users who need to determine the number types (integer or float) dynamically,
should review our section [dynamic number types](#dynamic-number-types). Indeed,
@@ -278,19 +319,35 @@ 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.
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
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
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
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:
`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()`,
`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 cast is not possible.
the number, string or boolean will be parsed, or the initial `{` or `[` will be verified for ondemand::object and ondemand::array. An exception is thrown if
the cast is not possible. Importantly, when getting an ondemand::object or ondemand::array instance, its content is
not validated: you are only guaranteed that the corresponding initial character (`{` or `[`) is present. Thus,
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
> parsed a value (such as by casting to double), you cannot get at it again. It is an error to call
@@ -298,12 +355,14 @@ support for users who avoid exceptions. See [the simdjson error handling documen
* **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
comparison. 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
object twice: `std::string_view(object["foo"]` followed by `std::string_view(object["foo"]`, your code
is in error. Furthermore, you can only consume one field at a time, on the same object. Thus
if you have retrieved `content["bids"].get_array()` and you later call `content["asks"].get_array()`, then the
first array should no longer be accessed: it would be unsafe to do so. You can detect such mistakes by first
compiling and running the code in Debug mode: an OUT_OF_ORDER_ITERATION error is generated.
not do `object["foo"]` followed by `object["foo"]` with the same `object` instance. Keep in mind that On Demand does not buffer or save the result of the parsing: if you repeatedly access `object["foo"]`, then it must repeatedly seek the key and parse the content. The library does not provide a distinct function to check if a key is present, instead we recommend you attempt to access the key: e.g., by doing `ondemand::value val{}; if(!object["foo"].get(val)) {...}`, you have that `val` contains the requested value inside the if clause. It is your responsability as a user to temporarily keep a reference to the value (`auto v = object["foo"]`), or to consume the content and store it in your own data structures. If you consume an
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
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
`content["asks"].get_array()`, then the first array should no longer be accessed: it would be
unsafe to do so. You can detect such mistakes by first compiling and running the code in
Debug mode: an OUT_OF_ORDER_ITERATION error is generated.
> NOTE: JSON allows you to escape characters in keys. E.g., the key `"date"` may be written as
> `"\u0064\u0061\u0074\u0065"`. By default, simdjson does *not* unescape keys when matching by default.
@@ -312,8 +371,9 @@ support for users who avoid exceptions. See [the simdjson error handling documen
> 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`
> instance. You should expect a performance penalty when using `unescaped_key()`.
>
> ```c++
> auto json = R"({"k\u0065y": 1})"_padded;
> auto json = R"({"k\u0065y": 1})"_padded;
> ondemand::parser parser;
> auto doc = parser.iterate(json);
> ondemand::object object = doc.get_object();
@@ -420,11 +480,12 @@ 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*.
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.
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
whole array. You may use it as follows if your document is itself an array:
whole array. You should only call `count_elements` as a last resort as it may
require scanning the document twice or more. You may use it as follows if your document is itself an array:
```C++
auto cars_json = R"( [ 40.1, 39.9, 37.7, 40.4 ] )"_padded;
@@ -444,14 +505,15 @@ support for users who avoid exceptions. See [the simdjson error handling documen
size_t count = test_array.count_elements(); // requires simdjson 1.0 or better
std::cout << "Number of elements: " << count << std::endl;
for(ondemand::object elem: test_array) {
std::cout << simdjson::to_string(elem);
std::cout << simdjson::to_json_string(elem);
}
```
* **Counting fields in objects:** Other times, it is useful to scan an object to determine the number of fields prior to
parsing it.
For this purpose, `object` instances have a `count_fields` method. Again, users should be
aware that the `count_fields` method can be costly since it requires scanning the
whole objects. You may use it as follows if your document is itself an object:
whole objects. You should only call `count_fields` as a last resort as it may
require scanning the document twice or more. You may use it as follows if your document is itself an object:
```C++
ondemand::parser parser;
@@ -471,8 +533,20 @@ support for users who avoid exceptions. See [the simdjson error handling documen
std::cout << "Number of fields: " << count << std::endl; // Prints "Number of fields: 2"
```
* **Tree Walking and JSON Element Types:** Sometimes you don't necessarily have a document
with a known type, and are trying to generically inspect or walk over JSON elements. To do that, you can use iterators and the `type()` method. You can also represent arbitrary JSON values with
`ondemand::value` instances: it can represent anything except a scalar document (lone number, string, null or Boolean). You can check for scalar documents with the method `scalar()`. You may also access [raw strings](#raw-strings).
with a known type, and are trying to generically inspect or walk over JSON elements.
You can also represent arbitrary JSON values with
`ondemand::value` instances: it can represent anything except a scalar document (lone number, string, null or Boolean). You can check for scalar documents with the method `scalar()`.
You can query the type of a document or a value with the `type()` method.
The `type()` method does not consume or validate documents and values, but it tells you whether they are
- arrays (`json_type::array`),
- objects (`json_type::object`)
- numbers (`json_type::number`),
- strings (`json_type::string`),
- Booleans (`json_type::boolean`),
- null (`json_type::null`).
You must still validate and consume the values (e.g., call `is_null()`) after calling `type()`.
You may also access [raw strings](#raw-strings).
For example, the following is a quick and dirty recursive function that verbosely prints the JSON document as JSON. This example also illustrates lifecycle requirements: the `document` instance holds the iterator. The document must remain in scope while you are accessing instances of `value`, `object` and `array`.
```c++
void recursive_print_json(ondemand::value element) {
@@ -521,7 +595,11 @@ support for users who avoid exceptions. See [the simdjson error handling documen
cout << element.get_bool();
break;
case ondemand::json_type::null:
cout << "null";
// We check that the value is indeed null
// otherwise: an error is thrown.
if(element.is_null()) {
cout << "null";
}
break;
}
}
@@ -586,6 +664,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.
```C++
@@ -920,11 +1033,11 @@ bool parse() {
// Iterating through an array of objects
auto error = parser.iterate(cars_json).get(doc);
if(error) { std::cerr << error << std::endl; return false; }
ondemand::array cars;
ondemand::array cars; // invalid until the get() succeeds
error = doc.get_array().get(cars);
for (auto car_value : cars) {
ondemand::object car;
ondemand::object car; // invalid until the get() succeeds
error = car_value.get_object().get(car);
if(error) { std::cerr << error << std::endl; return false; }
@@ -939,7 +1052,7 @@ bool parse() {
cout << "Make/Model: " << make << "/" << model << endl;
// Casting a JSON element to an integer
uint64_t year;
uint64_t year{};
error = car["year"].get(year);
if(error) { std::cerr << error << std::endl; return false; }
cout << "- This car is " << 2020 - year << " years old." << endl;
@@ -961,6 +1074,19 @@ bool parse() {
}
```
For safety, you should only use our ondemand instances (e.g., `ondemand::object`)
after you have initialized them and checked that there is no error:
```c++
ondemand::object car; // invalid until the get() succeeds
// the `car` instance should not use used before it is initialized
error = car_value.get_object().get(car);
if(error) {
// the `car` instance should not use used
} else {
// the `car` instance can be safely used
}
```
The following examples illustrates how to iterate through the content of an object without
having to handle exceptions.
@@ -970,10 +1096,12 @@ having to handle exceptions.
ondemand::document doc;
auto error = parser.iterate(json).get(doc);
if(error) { return false; }
ondemand::object object;
ondemand::object object; // invalid until the get() succeeds
error = doc.get_object().get(object);
if(error) { return false; }
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;
error = field.key().get(keyv);
if(error) { return false; }
@@ -999,7 +1127,7 @@ target_compile_definitions(simdjson PUBLIC SIMDJSON_EXCEPTIONS=OFF)
Users more comfortable with an exception flow may choose to directly cast the `simdjson_result<T>` to the desired type:
```c++
simdjson::ondemande::document doc = parser.iterate(json); // Throws an exception if there was an error!
simdjson::ondemand::document doc = parser.iterate(json); // Throws an exception if there was an error!
```
When used this way, a `simdjson_error` exception will be thrown if an error occurs, preventing the
@@ -1022,10 +1150,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
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
use the `const char *` pointer as a C string. As an example, consider the following
example where we used the exception-free simdjson interface:
@@ -1038,6 +1188,12 @@ int64_t i;
auto error = doc["integer"].get_int64().get(i); // Expect to get integer from "integer" key, but get TAPE_ERROR
if (error) {
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)
}
```
@@ -1086,6 +1242,9 @@ for (auto val : doc) {
std::cout << doc.current_location() << std::endl; // Throws OUT_OF_BOUNDS
```
Conversely, if `doc.current_location().error() == simdjson::SUCCESS`,
then the document has more content.
Finally, the `current_location()` method may also be used even when no exceptions/errors
are thrown. This can be helpful for users that want to know the current state of iteration during parsing. For example:
@@ -1094,7 +1253,7 @@ auto json = R"( [[1,2,3], -23.4, {"key": "value"}, true] )"_padded;
ondemand::parser parser;
auto doc = parser.iterate(json);
for (auto val : doc) {
ondemand::object obj;
ondemand::object obj; // invalid until the get() succeeds
auto error = val.get_object().get(obj); // Only get objects
if (!error) {
std::cout << doc.current_location() << std::endl; // Prints ""key": "value"}, true] "
@@ -1111,6 +1270,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
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
----------
@@ -1149,41 +1334,6 @@ internal string buffer. Thus you should consume values only 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.
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
----------------------------------------------
@@ -1372,6 +1522,8 @@ if (error) {
It is also important to note that when dealing an invalid number inside a string, simdjson will report a `NUMBER_ERROR` error if the string begins with a number whereas simdjson
will report a `INCORRECT_TYPE` error otherwise.
The `*_in_string` methods can also be called on a single document instance:
e.g., when your document consist solely of a quoted number.
Dynamic Number Types
------------------------------
@@ -1486,6 +1638,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
-------------
@@ -1507,7 +1731,7 @@ Standard Compliance
The simdjson library is fully compliant with the [RFC 8259](https://www.tbray.org/ongoing/When/201x/2017/12/14/rfc8259.html) JSON specification.
- The only insignificant whitespace characters allowed are the space, the horizontal tab, the line feed and the carriage return. In particular, a JSON document may not contain an unespaced null character.
- The only insignificant whitespace characters allowed are the space, the horizontal tab, the line feed and the carriage return. In particular, a JSON document may not contain an unescaped null character.
- A single string or a single number is considered to be a valid JSON document.
- We fully validate the numbers according to the JSON specification. For example, the string `01` is not valid JSON document since the specification states that *leading zeros are not allowed*.
- The specification allows implementations to set limits on the range and precision of numbers accepted. We support 64-bit floating-point numbers as well as integer values.
@@ -1526,3 +1750,215 @@ Backwards Compatibility
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
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;
}
```
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.
- 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 logs output will show step-by-step information on state, buffer pointer position, depth, and key retrieval status. The log level is set to `INFO` by default, but can be modified with the environment variable `SIMDJSON_LOG_LEVEL`. Setting the environment variable `SIMDJSON_LOG_LEVEL` to `ERROR` will log only errors.
+1 -1
View File
@@ -1,5 +1,5 @@
We take our documentation seriously. Please start reading the documentation before you attempt to use simdjson. We hope you will enjoy reading us.
* Basics: https://github.com/simdjson/simdjson/blob/master/doc/basics.md is an overview of how to use simdjson and its APIs.
* parse_many: https://github.com/simdjson/simdjson/blob/master/doc/parse_many.md describes an interface providing features to work with files or streams containing multiple small JSON documents. As fast and convenient as possible.
* iterate_many: https://github.com/simdjson/simdjson/blob/master/doc/iterate_many.md describes an interface providing features to work with files or streams containing multiple small JSON documents. As fast and convenient as possible.
* Performance: https://github.com/simdjson/simdjson/blob/master/doc/performance.md shows some more advanced scenarios and how to tune for them.
+34 -12
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)
* [Best Use of the DOM API](#best-use-of-the-dom-api)
* [Padding and Temporary Copies](#padding-and-temporary-copies)
* [Performance Tips](#performance-tips)
DOM vs On Demand
----------------------------------------------
@@ -44,10 +45,24 @@ dom::parser parser;
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.
You cannot copy a `parser` instance, you may only move it.
If you need to keep a document around long term, you can keep or move the parser instance. Note that moving a parser instance, or keeping one in a movable data structure like vector or map, can cause any outstanding `element`, `object` or `array` instances to be invalidated. If you need to store a parser in a movable data structure, you should use a `std::unique_ptr` to avoid this invalidation(e.g., `std::unique_ptr<dom::parser> parser(new dom::parser{})`).
If you need to keep a document around long term, you can keep or move the parser instance. Note that moving a parser instance, or keeping one in a movable data structure like vector or map, can cause any outstanding `element`, `object` or `array` instances to be invalidated. The `element`, `object` or `array` instances are mere thin wrappers akin to an `std::vector<int>::iterator`: they are invalid when default constructed, they must be tied to a valid document instance. If you need to store a parser in a movable data structure, you should use a `std::unique_ptr` to avoid this invalidation(e.g., `std::unique_ptr<dom::parser> parser(new dom::parser{})`).
During the`load` or `parse` calls, neither the input file nor the input string are ever modified. After calling `load` or `parse`, the source (either a file or a string) can be safely discarded. All of the JSON data is stored in the `parser` instance. The parsed document is also immutable in simdjson: you do not modify it by accessing it.
@@ -65,7 +80,7 @@ Once you have an element, you can navigate it with idiomatic C++ iterators, oper
* **Extracting Values (with exceptions):** You can cast a JSON element to a native type: `double(element)` or
`double x = json_element`. This works for double, uint64_t, int64_t, bool,
dom::object and dom::array. An exception (`simdjson::simdjson_error`) is thrown if the cast is not possible.
* **Extracting Values (without exceptions):** You can use a variant usage of `get()` with error codes to avoid exceptions. You first declare the variable of the appropriate type (`double`, `uint64_t`, `int64_t`, `bool`,
* **Extracting Values (without exceptions):** You can use a variant usage of `get()` with error codes to avoid exceptions. You first declare the variable of the appropriate type (`double`, `uint64_t`, `int64_t`, `bool`, `std::string_view`,
`dom::object` and `dom::array`) and pass it by reference to `get()` which gives you back an error code: e.g.,
```c++
simdjson::error_code error;
@@ -76,6 +91,7 @@ Once you have an element, you can navigate it with idiomatic C++ iterators, oper
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
std::cout << "I parsed " << value << " from " << numberstring.data() << std::endl;
```
The strings contain unescaped valid UTF-8 strings: no unmatched surrogate is allowed.
* **Field Access:** To get the value of the "foo" field in an object, use `object["foo"]`.
* **Array Iteration:** To iterate through an array, use `for (auto value : array) { ... }`. If you
know the type of the value, you can cast it right there, too! `for (double value : array) { ... }`
@@ -88,7 +104,7 @@ Once you have an element, you can navigate it with idiomatic C++ iterators, oper
* **Array and Object size** Given an array or an object, you can get its size (number of elements or keys)
with the `size()` method.
* **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::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`).
### Examples
@@ -167,7 +183,7 @@ While the simdjson library can be used in any project using C++ 11 and above, fi
```c++
padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded;
dom::parser parser;
dom::object object;
dom::object object; // invalid until the get() succeeds
auto error = parser.parse(json).get(object);
if (error) { cerr << error << endl; return; }
for (auto [key, value] : object) {
@@ -181,7 +197,7 @@ For comparison, here is the C++ 11 version of the same code:
// C++ 11 version for comparison
padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded;
dom::parser parser;
dom::object object;
dom::object object; // invalid until the get() succeeds
auto error = parser.parse(json).get(object);
if (error) { cerr << error << endl; return; }
for (dom::key_value_pair field : object) {
@@ -227,7 +243,7 @@ dom::parser parser;
dom::element cars = parser.parse(cars_json);
cout << cars.at_pointer("/0/tire_pressure/1") << endl; // Prints 39.9
for (dom::element car_element : cars) {
dom::object car;
dom::object car; // invalid until the get() succeeds
simdjson::error_code error;
if ((error = car_element.get(car))) { std::cerr << error << std::endl; return; }
double x = car.at_pointer("/tire_pressure/1");
@@ -283,11 +299,11 @@ it selects the key "count" within that object.
int main(void) {
simdjson::dom::parser parser;
simdjson::dom::element tweets;
simdjson::dom::element tweets; // invalid until the get() succeeds
auto error = parser.load("twitter.json").get(tweets);
if (error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
simdjson::dom::element res;
simdjson::dom::element res; // invalid until the get() succeeds
if ((error = tweets["search_metadata"]["count"].get(res))) {
std::cerr << "could not access keys" << std::endl;
return EXIT_FAILURE;
@@ -311,7 +327,7 @@ Observe how we use the `at` method when querying an index into an array, and not
int main(void) {
simdjson::dom::parser parser;
simdjson::dom::element tweets;
simdjson::dom::element tweets; // invalid until the get() succeeds
auto error = parser.load("twitter.json").get(tweets);
if(error) { std::cerr << error << std::endl; return EXIT_FAILURE; }
uint64_t identifier;
@@ -336,7 +352,7 @@ auto cars_json = R"( [
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
dom::parser parser;
dom::array cars;
dom::array cars; // invalid until the get() succeeds
auto error = parser.parse(cars_json).get(cars);
if (error) { cerr << error << endl; exit(1); }
@@ -382,7 +398,7 @@ auto abstract_json = R"( [
{ "12545" : {"a":11.44, "b":12.78, "c": 11111111} }
] )"_padded;
dom::parser parser;
dom::array array;
dom::array array; // invalid until after the next line
auto error = parser.parse(abstract_json).get(array);
if (error) { cerr << error << endl; exit(1); }
// Iterate through an array of objects
@@ -436,7 +452,7 @@ bool parse_double(const char *j, double &d) {
bool parse_string(const char *j, std::string &s) {
std::string_view answer;
auto error = parser.parse(j,strlen(j))
auto error = parser.parse(j, strlen(j))
.at(0)
.get(answer, error);
if (error) { return false; }
@@ -643,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.
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.
+5 -4
View File
@@ -21,12 +21,13 @@ The current implementations are:
* haswell: AVX2 (2013 Intel Haswell or later)
* westmere: SSE4.2 (2010 Westmere or later).
* 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.
* 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.
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
(haswell, westmere and fallback), on ARM it will include 2 (arm64 and fallback), and on PPC it will include 2 (ppc64 and fallback).
compiles *all* the implementations into the executable. On Intel, it will include 4 implementations
(icelake, haswell, westmere and fallback), on ARM it will include 2 (arm64 and fallback), and on PPC
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
these implementations at compile time with `-DSIMDJSON_IMPLEMENTATION_X=0` (where X is ICELAKE, HASWELL,
@@ -51,7 +52,7 @@ Inspecting the Detected Implementation
You can check what implementation is running with `active_implementation`:
```c++
cout << "simdjson v" << SIMDJSON_STRINGIFY(SIMDJSON_VERSION) << endl;
cout << "simdjson v" << SIMDJSON_VERSION << endl;
cout << "Detected the best implementation for your machine: " << simdjson::get_active_implementation()->name();
cout << "(" << simdjson::get_active_implementation()->description() << ")" << endl;
```
+5
View File
@@ -237,3 +237,8 @@ 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.
Comma separated documents
-----------
`iterate_many` also takes in an option to allow parsing of comma separated documents. In this mode, the entire buffer is processed in 1 batch and batch size will be increased to be as large as the JSON passed. Therefore, the capacity of the parser has to be sufficient to support the batch size set.
+1 -1
View File
@@ -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.
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++
std::cout << simdjson::builtin_implementation()->name() << 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
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 string buffers](#reusing-string-buffers)
* [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)
* [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
-----------------------------------------
@@ -138,7 +153,7 @@ few hundred megabytes per second if your JSON documents are densely packed with
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.
@@ -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 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
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 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
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.
+11 -7
View File
@@ -9,7 +9,11 @@ namespace {
// but the algorithms do not end up using the returned value.
// Sadly, sanitizers are not smart enough to figure it out.
SIMDJSON_NO_SANITIZE_UNDEFINED
simdjson_really_inline int trailing_zeroes(uint64_t input_num) {
// 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) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
unsigned long ret;
// Search the mask data from least significant bit (LSB)
@@ -22,12 +26,12 @@ simdjson_really_inline int trailing_zeroes(uint64_t input_num) {
}
/* result might be undefined when input_num is zero */
simdjson_really_inline uint64_t clear_lowest_bit(uint64_t input_num) {
simdjson_inline uint64_t clear_lowest_bit(uint64_t input_num) {
return input_num & (input_num-1);
}
/* result might be undefined when input_num is zero */
simdjson_really_inline int leading_zeroes(uint64_t input_num) {
simdjson_inline int leading_zeroes(uint64_t input_num) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
unsigned long leading_zero = 0;
// Search the mask data from most significant bit (MSB)
@@ -42,7 +46,7 @@ simdjson_really_inline int leading_zeroes(uint64_t input_num) {
}
/* result might be undefined when input_num is zero */
simdjson_really_inline int count_ones(uint64_t input_num) {
simdjson_inline int count_ones(uint64_t input_num) {
return vaddv_u8(vcnt_u8(vcreate_u8(input_num)));
}
@@ -61,7 +65,7 @@ simdjson_really_inline int count_ones(uint64_t input_num) {
#define SIMDJSON_PREFER_REVERSE_BITS 1
/* reverse the bits */
simdjson_really_inline uint64_t reverse_bits(uint64_t input_num) {
simdjson_inline uint64_t reverse_bits(uint64_t input_num) {
uint64_t rev_bits;
__asm("rbit %0, %1" : "=r"(rev_bits) : "r"(input_num));
return rev_bits;
@@ -74,13 +78,13 @@ simdjson_really_inline uint64_t reverse_bits(uint64_t input_num) {
* of such undefined behavior is never used.
**/
SIMDJSON_NO_SANITIZE_UNDEFINED
simdjson_really_inline uint64_t zero_leading_bit(uint64_t rev_bits, int leading_zeroes) {
simdjson_inline uint64_t zero_leading_bit(uint64_t rev_bits, int leading_zeroes) {
return rev_bits ^ (uint64_t(0x8000000000000000) >> leading_zeroes);
}
#endif
simdjson_really_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) {
simdjson_inline bool add_overflow(uint64_t value1, uint64_t value2, uint64_t *result) {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
*result = value1 + value2;
return *result < value1;
+1 -1
View File
@@ -10,7 +10,7 @@ namespace {
//
// For example, prefix_xor(00100100) == 00011100
//
simdjson_really_inline uint64_t prefix_xor(uint64_t bitmask) {
simdjson_inline uint64_t prefix_xor(uint64_t bitmask) {
/////////////
// We could do this with PMULL, but it is apparently slow.
//
+4 -1
View File
@@ -12,9 +12,12 @@ using namespace simdjson;
using namespace simdjson::dom;
}
/**
* @private
*/
class implementation final : public simdjson::implementation {
public:
simdjson_really_inline implementation() : simdjson::implementation("arm64", "ARM NEON", internal::instruction_set::NEON) {}
simdjson_inline implementation() : simdjson::implementation("arm64", "ARM NEON", internal::instruction_set::NEON) {}
simdjson_warn_unused error_code create_dom_parser_implementation(
size_t capacity,
size_t max_length,
+1 -1
View File
@@ -7,7 +7,7 @@ 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_really_inline uint32_t parse_eight_digits_unrolled(const uint8_t *chars) {
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;
+95 -95
View File
@@ -28,7 +28,7 @@ namespace {
* You should not use this function except for compile-time constants:
* it is not efficient.
*/
simdjson_really_inline uint8x16_t make_uint8x16_t(uint8_t x1, uint8_t x2, uint8_t x3, uint8_t x4,
simdjson_inline uint8x16_t make_uint8x16_t(uint8_t x1, uint8_t x2, uint8_t x3, uint8_t x4,
uint8_t x5, uint8_t x6, uint8_t x7, uint8_t x8,
uint8_t x9, uint8_t x10, uint8_t x11, uint8_t x12,
uint8_t x13, uint8_t x14, uint8_t x15, uint8_t x16) {
@@ -57,7 +57,7 @@ simdjson_really_inline uint8x16_t make_uint8x16_t(uint8_t x1, uint8_t x2, uint
return x;
}
simdjson_really_inline uint8x8_t make_uint8x8_t(uint8_t x1, uint8_t x2, uint8_t x3, uint8_t x4,
simdjson_inline uint8x8_t make_uint8x8_t(uint8_t x1, uint8_t x2, uint8_t x3, uint8_t x4,
uint8_t x5, uint8_t x6, uint8_t x7, uint8_t x8) {
uint8x8_t x{};
x = vset_lane_u8(x1, x, 0);
@@ -72,7 +72,7 @@ simdjson_really_inline uint8x8_t make_uint8x8_t(uint8_t x1, uint8_t x2, uint8_
}
// We have to do the same work for make_int8x16_t
simdjson_really_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int8_t x4,
simdjson_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x3, int8_t x4,
int8_t x5, int8_t x6, int8_t x7, int8_t x8,
int8_t x9, int8_t x10, int8_t x11, int8_t x12,
int8_t x13, int8_t x14, int8_t x15, int8_t x16) {
@@ -118,24 +118,24 @@ simdjson_really_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x
static const int SIZE = sizeof(value);
// Conversion from/to SIMD register
simdjson_really_inline base_u8(const uint8x16_t _value) : value(_value) {}
simdjson_really_inline operator const uint8x16_t&() const { return this->value; }
simdjson_really_inline operator uint8x16_t&() { return this->value; }
simdjson_inline base_u8(const uint8x16_t _value) : value(_value) {}
simdjson_inline operator const uint8x16_t&() const { return this->value; }
simdjson_inline operator uint8x16_t&() { return this->value; }
// Bit operations
simdjson_really_inline simd8<T> operator|(const simd8<T> other) const { return vorrq_u8(*this, other); }
simdjson_really_inline simd8<T> operator&(const simd8<T> other) const { return vandq_u8(*this, other); }
simdjson_really_inline simd8<T> operator^(const simd8<T> other) const { return veorq_u8(*this, other); }
simdjson_really_inline simd8<T> bit_andnot(const simd8<T> other) const { return vbicq_u8(*this, other); }
simdjson_really_inline simd8<T> operator~() const { return *this ^ 0xFFu; }
simdjson_really_inline simd8<T>& operator|=(const simd8<T> other) { auto this_cast = static_cast<simd8<T>*>(this); *this_cast = *this_cast | other; return *this_cast; }
simdjson_really_inline simd8<T>& operator&=(const simd8<T> other) { auto this_cast = static_cast<simd8<T>*>(this); *this_cast = *this_cast & other; return *this_cast; }
simdjson_really_inline simd8<T>& operator^=(const simd8<T> other) { auto this_cast = static_cast<simd8<T>*>(this); *this_cast = *this_cast ^ other; return *this_cast; }
simdjson_inline simd8<T> operator|(const simd8<T> other) const { return vorrq_u8(*this, other); }
simdjson_inline simd8<T> operator&(const simd8<T> other) const { return vandq_u8(*this, other); }
simdjson_inline simd8<T> operator^(const simd8<T> other) const { return veorq_u8(*this, other); }
simdjson_inline simd8<T> bit_andnot(const simd8<T> other) const { return vbicq_u8(*this, other); }
simdjson_inline simd8<T> operator~() const { return *this ^ 0xFFu; }
simdjson_inline simd8<T>& operator|=(const simd8<T> other) { auto this_cast = static_cast<simd8<T>*>(this); *this_cast = *this_cast | other; return *this_cast; }
simdjson_inline simd8<T>& operator&=(const simd8<T> other) { auto this_cast = static_cast<simd8<T>*>(this); *this_cast = *this_cast & other; return *this_cast; }
simdjson_inline simd8<T>& operator^=(const simd8<T> other) { auto this_cast = static_cast<simd8<T>*>(this); *this_cast = *this_cast ^ other; return *this_cast; }
friend simdjson_really_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) { return vceqq_u8(lhs, rhs); }
friend simdjson_inline Mask operator==(const simd8<T> lhs, const simd8<T> rhs) { return vceqq_u8(lhs, rhs); }
template<int N=1>
simdjson_really_inline simd8<T> prev(const simd8<T> prev_chunk) const {
simdjson_inline simd8<T> prev(const simd8<T> prev_chunk) const {
return vextq_u8(prev_chunk, *this, 16 - N);
}
};
@@ -146,17 +146,17 @@ simdjson_really_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x
typedef uint16_t bitmask_t;
typedef uint32_t bitmask2_t;
static simdjson_really_inline simd8<bool> splat(bool _value) { return vmovq_n_u8(uint8_t(-(!!_value))); }
static simdjson_inline simd8<bool> splat(bool _value) { return vmovq_n_u8(uint8_t(-(!!_value))); }
simdjson_really_inline simd8(const uint8x16_t _value) : base_u8<bool>(_value) {}
simdjson_inline simd8(const uint8x16_t _value) : base_u8<bool>(_value) {}
// False constructor
simdjson_really_inline simd8() : simd8(vdupq_n_u8(0)) {}
simdjson_inline simd8() : simd8(vdupq_n_u8(0)) {}
// Splat constructor
simdjson_really_inline simd8(bool _value) : simd8(splat(_value)) {}
simdjson_inline simd8(bool _value) : simd8(splat(_value)) {}
// We return uint32_t instead of uint16_t because that seems to be more efficient for most
// purposes (cutting it down to uint16_t costs performance in some compilers).
simdjson_really_inline uint32_t to_bitmask() const {
simdjson_inline uint32_t to_bitmask() const {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
const uint8x16_t bit_mask = make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80);
@@ -170,26 +170,26 @@ simdjson_really_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x
tmp = vpaddq_u8(tmp, tmp);
return vgetq_lane_u16(vreinterpretq_u16_u8(tmp), 0);
}
simdjson_really_inline bool any() const { return vmaxvq_u8(*this) != 0; }
simdjson_inline bool any() const { return vmaxvq_u8(*this) != 0; }
};
// Unsigned bytes
template<>
struct simd8<uint8_t>: base_u8<uint8_t> {
static simdjson_really_inline uint8x16_t splat(uint8_t _value) { return vmovq_n_u8(_value); }
static simdjson_really_inline uint8x16_t zero() { return vdupq_n_u8(0); }
static simdjson_really_inline uint8x16_t load(const uint8_t* values) { return vld1q_u8(values); }
static simdjson_inline uint8x16_t splat(uint8_t _value) { return vmovq_n_u8(_value); }
static simdjson_inline uint8x16_t zero() { return vdupq_n_u8(0); }
static simdjson_inline uint8x16_t load(const uint8_t* values) { return vld1q_u8(values); }
simdjson_really_inline simd8(const uint8x16_t _value) : base_u8<uint8_t>(_value) {}
simdjson_inline simd8(const uint8x16_t _value) : base_u8<uint8_t>(_value) {}
// Zero constructor
simdjson_really_inline simd8() : simd8(zero()) {}
simdjson_inline simd8() : simd8(zero()) {}
// Array constructor
simdjson_really_inline simd8(const uint8_t values[16]) : simd8(load(values)) {}
simdjson_inline simd8(const uint8_t values[16]) : simd8(load(values)) {}
// Splat constructor
simdjson_really_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
simdjson_inline simd8(uint8_t _value) : simd8(splat(_value)) {}
// Member-by-member initialization
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
simdjson_really_inline simd8(
simdjson_inline simd8(
uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7,
uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
) : simd8(make_uint8x16_t(
@@ -197,7 +197,7 @@ simdjson_really_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x
v8, v9, v10,v11,v12,v13,v14,v15
)) {}
#else
simdjson_really_inline simd8(
simdjson_inline simd8(
uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7,
uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
) : simd8(uint8x16_t{
@@ -207,7 +207,7 @@ simdjson_really_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x
#endif
// Repeat 16 values as many times as necessary (usually for lookup tables)
simdjson_really_inline static simd8<uint8_t> repeat_16(
simdjson_inline static simd8<uint8_t> repeat_16(
uint8_t v0, uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4, uint8_t v5, uint8_t v6, uint8_t v7,
uint8_t v8, uint8_t v9, uint8_t v10, uint8_t v11, uint8_t v12, uint8_t v13, uint8_t v14, uint8_t v15
) {
@@ -218,44 +218,44 @@ simdjson_really_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x
}
// Store to array
simdjson_really_inline void store(uint8_t dst[16]) const { return vst1q_u8(dst, *this); }
simdjson_inline void store(uint8_t dst[16]) const { return vst1q_u8(dst, *this); }
// Saturated math
simdjson_really_inline simd8<uint8_t> saturating_add(const simd8<uint8_t> other) const { return vqaddq_u8(*this, other); }
simdjson_really_inline simd8<uint8_t> saturating_sub(const simd8<uint8_t> other) const { return vqsubq_u8(*this, other); }
simdjson_inline simd8<uint8_t> saturating_add(const simd8<uint8_t> other) const { return vqaddq_u8(*this, other); }
simdjson_inline simd8<uint8_t> saturating_sub(const simd8<uint8_t> other) const { return vqsubq_u8(*this, other); }
// Addition/subtraction are the same for signed and unsigned
simdjson_really_inline simd8<uint8_t> operator+(const simd8<uint8_t> other) const { return vaddq_u8(*this, other); }
simdjson_really_inline simd8<uint8_t> operator-(const simd8<uint8_t> other) const { return vsubq_u8(*this, other); }
simdjson_really_inline simd8<uint8_t>& operator+=(const simd8<uint8_t> other) { *this = *this + other; return *this; }
simdjson_really_inline simd8<uint8_t>& operator-=(const simd8<uint8_t> other) { *this = *this - other; return *this; }
simdjson_inline simd8<uint8_t> operator+(const simd8<uint8_t> other) const { return vaddq_u8(*this, other); }
simdjson_inline simd8<uint8_t> operator-(const simd8<uint8_t> other) const { return vsubq_u8(*this, other); }
simdjson_inline simd8<uint8_t>& operator+=(const simd8<uint8_t> other) { *this = *this + other; return *this; }
simdjson_inline simd8<uint8_t>& operator-=(const simd8<uint8_t> other) { *this = *this - other; return *this; }
// Order-specific operations
simdjson_really_inline uint8_t max_val() const { return vmaxvq_u8(*this); }
simdjson_really_inline uint8_t min_val() const { return vminvq_u8(*this); }
simdjson_really_inline simd8<uint8_t> max_val(const simd8<uint8_t> other) const { return vmaxq_u8(*this, other); }
simdjson_really_inline simd8<uint8_t> min_val(const simd8<uint8_t> other) const { return vminq_u8(*this, other); }
simdjson_really_inline simd8<bool> operator<=(const simd8<uint8_t> other) const { return vcleq_u8(*this, other); }
simdjson_really_inline simd8<bool> operator>=(const simd8<uint8_t> other) const { return vcgeq_u8(*this, other); }
simdjson_really_inline simd8<bool> operator<(const simd8<uint8_t> other) const { return vcltq_u8(*this, other); }
simdjson_really_inline simd8<bool> operator>(const simd8<uint8_t> other) const { return vcgtq_u8(*this, other); }
simdjson_inline uint8_t max_val() const { return vmaxvq_u8(*this); }
simdjson_inline uint8_t min_val() const { return vminvq_u8(*this); }
simdjson_inline simd8<uint8_t> max_val(const simd8<uint8_t> other) const { return vmaxq_u8(*this, other); }
simdjson_inline simd8<uint8_t> min_val(const simd8<uint8_t> other) const { return vminq_u8(*this, other); }
simdjson_inline simd8<bool> operator<=(const simd8<uint8_t> other) const { return vcleq_u8(*this, other); }
simdjson_inline simd8<bool> operator>=(const simd8<uint8_t> other) const { return vcgeq_u8(*this, other); }
simdjson_inline simd8<bool> operator<(const simd8<uint8_t> other) const { return vcltq_u8(*this, other); }
simdjson_inline simd8<bool> operator>(const simd8<uint8_t> other) const { return vcgtq_u8(*this, other); }
// Same as >, but instead of guaranteeing all 1's == true, false = 0 and true = nonzero. For ARM, returns all 1's.
simdjson_really_inline simd8<uint8_t> gt_bits(const simd8<uint8_t> other) const { return simd8<uint8_t>(*this > other); }
simdjson_inline simd8<uint8_t> gt_bits(const simd8<uint8_t> other) const { return simd8<uint8_t>(*this > other); }
// Same as <, but instead of guaranteeing all 1's == true, false = 0 and true = nonzero. For ARM, returns all 1's.
simdjson_really_inline simd8<uint8_t> lt_bits(const simd8<uint8_t> other) const { return simd8<uint8_t>(*this < other); }
simdjson_inline simd8<uint8_t> lt_bits(const simd8<uint8_t> other) const { return simd8<uint8_t>(*this < other); }
// Bit-specific operations
simdjson_really_inline simd8<bool> any_bits_set(simd8<uint8_t> bits) const { return vtstq_u8(*this, bits); }
simdjson_really_inline bool any_bits_set_anywhere() const { return this->max_val() != 0; }
simdjson_really_inline bool any_bits_set_anywhere(simd8<uint8_t> bits) const { return (*this & bits).any_bits_set_anywhere(); }
simdjson_inline simd8<bool> any_bits_set(simd8<uint8_t> bits) const { return vtstq_u8(*this, bits); }
simdjson_inline bool any_bits_set_anywhere() const { return this->max_val() != 0; }
simdjson_inline bool any_bits_set_anywhere(simd8<uint8_t> bits) const { return (*this & bits).any_bits_set_anywhere(); }
template<int N>
simdjson_really_inline simd8<uint8_t> shr() const { return vshrq_n_u8(*this, N); }
simdjson_inline simd8<uint8_t> shr() const { return vshrq_n_u8(*this, N); }
template<int N>
simdjson_really_inline simd8<uint8_t> shl() const { return vshlq_n_u8(*this, N); }
simdjson_inline simd8<uint8_t> shl() const { return vshlq_n_u8(*this, N); }
// Perform a lookup assuming the value is between 0 and 16 (undefined behavior for out of range values)
template<typename L>
simdjson_really_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
simdjson_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
return lookup_table.apply_lookup_16_to(*this);
}
@@ -268,7 +268,7 @@ simdjson_really_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x
// signature simd8<L> compress(uint16_t mask) would be
// sensible, but the AVX ISA makes this kind of approach difficult.
template<typename L>
simdjson_really_inline void compress(uint16_t mask, L * output) const {
simdjson_inline void compress(uint16_t mask, L * output) const {
using internal::thintable_epi8;
using internal::BitsSetTable256mul2;
using internal::pshufb_combine_table;
@@ -305,7 +305,7 @@ simdjson_really_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x
// Copies all bytes corresponding to a 0 in the low half of the mask (interpreted as a
// bitset) to output1, then those corresponding to a 0 in the high half to output2.
template<typename L>
simdjson_really_inline void compress_halves(uint16_t mask, L *output1, L *output2) const {
simdjson_inline void compress_halves(uint16_t mask, L *output1, L *output2) const {
using internal::thintable_epi8;
uint8_t mask1 = uint8_t(mask); // least significant 8 bits
uint8_t mask2 = uint8_t(mask >> 8); // most significant 8 bits
@@ -324,7 +324,7 @@ simdjson_really_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x
}
template<typename L>
simdjson_really_inline simd8<L> lookup_16(
simdjson_inline simd8<L> lookup_16(
L replace0, L replace1, L replace2, L replace3,
L replace4, L replace5, L replace6, L replace7,
L replace8, L replace9, L replace10, L replace11,
@@ -338,7 +338,7 @@ simdjson_really_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x
}
template<typename T>
simdjson_really_inline simd8<uint8_t> apply_lookup_16_to(const simd8<T> original) {
simdjson_inline simd8<uint8_t> apply_lookup_16_to(const simd8<T> original) {
return vqtbl1q_u8(*this, simd8<uint8_t>(original));
}
};
@@ -348,24 +348,24 @@ simdjson_really_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x
struct simd8<int8_t> {
int8x16_t value;
static simdjson_really_inline simd8<int8_t> splat(int8_t _value) { return vmovq_n_s8(_value); }
static simdjson_really_inline simd8<int8_t> zero() { return vdupq_n_s8(0); }
static simdjson_really_inline simd8<int8_t> load(const int8_t values[16]) { return vld1q_s8(values); }
static simdjson_inline simd8<int8_t> splat(int8_t _value) { return vmovq_n_s8(_value); }
static simdjson_inline simd8<int8_t> zero() { return vdupq_n_s8(0); }
static simdjson_inline simd8<int8_t> load(const int8_t values[16]) { return vld1q_s8(values); }
// Conversion from/to SIMD register
simdjson_really_inline simd8(const int8x16_t _value) : value{_value} {}
simdjson_really_inline operator const int8x16_t&() const { return this->value; }
simdjson_really_inline operator int8x16_t&() { return this->value; }
simdjson_inline simd8(const int8x16_t _value) : value{_value} {}
simdjson_inline operator const int8x16_t&() const { return this->value; }
simdjson_inline operator int8x16_t&() { return this->value; }
// Zero constructor
simdjson_really_inline simd8() : simd8(zero()) {}
simdjson_inline simd8() : simd8(zero()) {}
// Splat constructor
simdjson_really_inline simd8(int8_t _value) : simd8(splat(_value)) {}
simdjson_inline simd8(int8_t _value) : simd8(splat(_value)) {}
// Array constructor
simdjson_really_inline simd8(const int8_t* values) : simd8(load(values)) {}
simdjson_inline simd8(const int8_t* values) : simd8(load(values)) {}
// Member-by-member initialization
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
simdjson_really_inline simd8(
simdjson_inline simd8(
int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5, int8_t v6, int8_t v7,
int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
) : simd8(make_int8x16_t(
@@ -373,7 +373,7 @@ simdjson_really_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x
v8, v9, v10,v11,v12,v13,v14,v15
)) {}
#else
simdjson_really_inline simd8(
simdjson_inline simd8(
int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5, int8_t v6, int8_t v7,
int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
) : simd8(int8x16_t{
@@ -382,7 +382,7 @@ simdjson_really_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x
}) {}
#endif
// Repeat 16 values as many times as necessary (usually for lookup tables)
simdjson_really_inline static simd8<int8_t> repeat_16(
simdjson_inline static simd8<int8_t> repeat_16(
int8_t v0, int8_t v1, int8_t v2, int8_t v3, int8_t v4, int8_t v5, int8_t v6, int8_t v7,
int8_t v8, int8_t v9, int8_t v10, int8_t v11, int8_t v12, int8_t v13, int8_t v14, int8_t v15
) {
@@ -393,7 +393,7 @@ simdjson_really_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x
}
// Store to array
simdjson_really_inline void store(int8_t dst[16]) const { return vst1q_s8(dst, *this); }
simdjson_inline void store(int8_t dst[16]) const { return vst1q_s8(dst, *this); }
// Explicit conversion to/from unsigned
//
@@ -401,35 +401,35 @@ simdjson_really_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x
// In theory, we could check this occurrence with std::same_as and std::enabled_if but it is C++14
// and relatively ugly and hard to read.
#ifndef SIMDJSON_REGULAR_VISUAL_STUDIO
simdjson_really_inline explicit simd8(const uint8x16_t other): simd8(vreinterpretq_s8_u8(other)) {}
simdjson_inline explicit simd8(const uint8x16_t other): simd8(vreinterpretq_s8_u8(other)) {}
#endif
simdjson_really_inline explicit operator simd8<uint8_t>() const { return vreinterpretq_u8_s8(this->value); }
simdjson_inline explicit operator simd8<uint8_t>() const { return vreinterpretq_u8_s8(this->value); }
// Math
simdjson_really_inline simd8<int8_t> operator+(const simd8<int8_t> other) const { return vaddq_s8(*this, other); }
simdjson_really_inline simd8<int8_t> operator-(const simd8<int8_t> other) const { return vsubq_s8(*this, other); }
simdjson_really_inline simd8<int8_t>& operator+=(const simd8<int8_t> other) { *this = *this + other; return *this; }
simdjson_really_inline simd8<int8_t>& operator-=(const simd8<int8_t> other) { *this = *this - other; return *this; }
simdjson_inline simd8<int8_t> operator+(const simd8<int8_t> other) const { return vaddq_s8(*this, other); }
simdjson_inline simd8<int8_t> operator-(const simd8<int8_t> other) const { return vsubq_s8(*this, other); }
simdjson_inline simd8<int8_t>& operator+=(const simd8<int8_t> other) { *this = *this + other; return *this; }
simdjson_inline simd8<int8_t>& operator-=(const simd8<int8_t> other) { *this = *this - other; return *this; }
// Order-sensitive comparisons
simdjson_really_inline simd8<int8_t> max_val(const simd8<int8_t> other) const { return vmaxq_s8(*this, other); }
simdjson_really_inline simd8<int8_t> min_val(const simd8<int8_t> other) const { return vminq_s8(*this, other); }
simdjson_really_inline simd8<bool> operator>(const simd8<int8_t> other) const { return vcgtq_s8(*this, other); }
simdjson_really_inline simd8<bool> operator<(const simd8<int8_t> other) const { return vcltq_s8(*this, other); }
simdjson_really_inline simd8<bool> operator==(const simd8<int8_t> other) const { return vceqq_s8(*this, other); }
simdjson_inline simd8<int8_t> max_val(const simd8<int8_t> other) const { return vmaxq_s8(*this, other); }
simdjson_inline simd8<int8_t> min_val(const simd8<int8_t> other) const { return vminq_s8(*this, other); }
simdjson_inline simd8<bool> operator>(const simd8<int8_t> other) const { return vcgtq_s8(*this, other); }
simdjson_inline simd8<bool> operator<(const simd8<int8_t> other) const { return vcltq_s8(*this, other); }
simdjson_inline simd8<bool> operator==(const simd8<int8_t> other) const { return vceqq_s8(*this, other); }
template<int N=1>
simdjson_really_inline simd8<int8_t> prev(const simd8<int8_t> prev_chunk) const {
simdjson_inline simd8<int8_t> prev(const simd8<int8_t> prev_chunk) const {
return vextq_s8(prev_chunk, *this, 16 - N);
}
// Perform a lookup assuming no value is larger than 16
template<typename L>
simdjson_really_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
simdjson_inline simd8<L> lookup_16(simd8<L> lookup_table) const {
return lookup_table.apply_lookup_16_to(*this);
}
template<typename L>
simdjson_really_inline simd8<L> lookup_16(
simdjson_inline simd8<L> lookup_16(
L replace0, L replace1, L replace2, L replace3,
L replace4, L replace5, L replace6, L replace7,
L replace8, L replace9, L replace10, L replace11,
@@ -443,7 +443,7 @@ simdjson_really_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x
}
template<typename T>
simdjson_really_inline simd8<int8_t> apply_lookup_16_to(const simd8<T> original) {
simdjson_inline simd8<int8_t> apply_lookup_16_to(const simd8<T> original) {
return vqtbl1q_s8(*this, simd8<uint8_t>(original));
}
};
@@ -458,22 +458,22 @@ simdjson_really_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x
simd8x64<T>& operator=(const simd8<T>& other) = delete; // no assignment allowed
simd8x64() = delete; // no default constructor allowed
simdjson_really_inline simd8x64(const simd8<T> chunk0, const simd8<T> chunk1, const simd8<T> chunk2, const simd8<T> chunk3) : chunks{chunk0, chunk1, chunk2, chunk3} {}
simdjson_really_inline simd8x64(const T ptr[64]) : chunks{simd8<T>::load(ptr), simd8<T>::load(ptr+16), simd8<T>::load(ptr+32), simd8<T>::load(ptr+48)} {}
simdjson_inline simd8x64(const simd8<T> chunk0, const simd8<T> chunk1, const simd8<T> chunk2, const simd8<T> chunk3) : chunks{chunk0, chunk1, chunk2, chunk3} {}
simdjson_inline simd8x64(const T ptr[64]) : chunks{simd8<T>::load(ptr), simd8<T>::load(ptr+16), simd8<T>::load(ptr+32), simd8<T>::load(ptr+48)} {}
simdjson_really_inline void store(T ptr[64]) const {
simdjson_inline void store(T ptr[64]) const {
this->chunks[0].store(ptr+sizeof(simd8<T>)*0);
this->chunks[1].store(ptr+sizeof(simd8<T>)*1);
this->chunks[2].store(ptr+sizeof(simd8<T>)*2);
this->chunks[3].store(ptr+sizeof(simd8<T>)*3);
}
simdjson_really_inline simd8<T> reduce_or() const {
simdjson_inline simd8<T> reduce_or() const {
return (this->chunks[0] | this->chunks[1]) | (this->chunks[2] | this->chunks[3]);
}
simdjson_really_inline uint64_t compress(uint64_t mask, T * output) const {
simdjson_inline uint64_t compress(uint64_t mask, T * output) const {
uint64_t popcounts = vget_lane_u64(vreinterpret_u64_u8(vcnt_u8(vcreate_u8(~mask))), 0);
// compute the prefix sum of the popcounts of each byte
uint64_t offsets = popcounts * 0x0101010101010101;
@@ -484,7 +484,7 @@ simdjson_really_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x
return offsets >> 56;
}
simdjson_really_inline uint64_t to_bitmask() const {
simdjson_inline uint64_t to_bitmask() const {
#ifdef SIMDJSON_REGULAR_VISUAL_STUDIO
const uint8x16_t bit_mask = make_uint8x16_t(
0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80,
@@ -504,7 +504,7 @@ simdjson_really_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x
return vgetq_lane_u64(vreinterpretq_u64_u8(sum0), 0);
}
simdjson_really_inline uint64_t eq(const T m) const {
simdjson_inline uint64_t eq(const T m) const {
const simd8<T> mask = simd8<T>::splat(m);
return simd8x64<bool>(
this->chunks[0] == mask,
@@ -514,7 +514,7 @@ simdjson_really_inline int8x16_t make_int8x16_t(int8_t x1, int8_t x2, int8_t x
).to_bitmask();
}
simdjson_really_inline uint64_t lteq(const T m) const {
simdjson_inline uint64_t lteq(const T m) const {
const simd8<T> mask = simd8<T>::splat(m);
return simd8x64<bool>(
this->chunks[0] <= mask,
+6 -8
View File
@@ -15,18 +15,18 @@ using namespace simd;
struct backslash_and_quote {
public:
static constexpr uint32_t BYTES_PROCESSED = 32;
simdjson_really_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst);
simdjson_inline static backslash_and_quote copy_and_find(const uint8_t *src, uint8_t *dst);
simdjson_really_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; }
simdjson_really_inline bool has_backslash() { return bs_bits != 0; }
simdjson_really_inline int quote_index() { return trailing_zeroes(quote_bits); }
simdjson_really_inline int backslash_index() { return trailing_zeroes(bs_bits); }
simdjson_inline bool has_quote_first() { return ((bs_bits - 1) & quote_bits) != 0; }
simdjson_inline bool has_backslash() { return bs_bits != 0; }
simdjson_inline int quote_index() { return trailing_zeroes(quote_bits); }
simdjson_inline int backslash_index() { return trailing_zeroes(bs_bits); }
uint32_t bs_bits;
uint32_t quote_bits;
}; // struct backslash_and_quote
simdjson_really_inline backslash_and_quote backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) {
simdjson_inline backslash_and_quote backslash_and_quote::copy_and_find(const uint8_t *src, uint8_t *dst) {
// this can read up to 31 bytes beyond the buffer size, but we require
// SIMDJSON_PADDING of padding
static_assert(SIMDJSON_PADDING >= (BYTES_PROCESSED - 1), "backslash and quote finder must process fewer than SIMDJSON_PADDING bytes");
@@ -48,6 +48,4 @@ simdjson_really_inline backslash_and_quote backslash_and_quote::copy_and_find(co
} // namespace SIMDJSON_IMPLEMENTATION
} // namespace simdjson
#include "simdjson/generic/stringparsing.h"
#endif // SIMDJSON_ARM64_STRINGPARSING_H
+49 -7
View File
@@ -70,7 +70,7 @@ constexpr size_t DEFAULT_MAX_DEPTH = 1024;
#define SIMDJSON_ISALIGNED_N(ptr, n) (((uintptr_t)(ptr) & ((n)-1)) == 0)
#if defined(SIMDJSON_REGULAR_VISUAL_STUDIO)
#if SIMDJSON_REGULAR_VISUAL_STUDIO
#define simdjson_really_inline __forceinline
#define simdjson_never_inline __declspec(noinline)
@@ -155,7 +155,7 @@ constexpr size_t DEFAULT_MAX_DEPTH = 1024;
#define SIMDJSON_PRAGMA(P) _Pragma(#P)
#define SIMDJSON_DISABLE_GCC_WARNING(WARNING) SIMDJSON_PRAGMA(GCC diagnostic ignored #WARNING)
#if defined(SIMDJSON_CLANG_VISUAL_STUDIO)
#if SIMDJSON_CLANG_VISUAL_STUDIO
#define SIMDJSON_DISABLE_UNDESIRED_WARNINGS SIMDJSON_DISABLE_GCC_WARNING(-Wmicrosoft-include)
#else
#define SIMDJSON_DISABLE_UNDESIRED_WARNINGS
@@ -168,7 +168,19 @@ constexpr size_t DEFAULT_MAX_DEPTH = 1024;
#endif // MSC_VER
#if defined(SIMDJSON_VISUAL_STUDIO)
#if defined(simdjson_inline)
// Prefer the user's definition of simdjson_inline; don't define it ourselves.
#elif defined(__GNUC__) && !defined(__OPTIMIZE__)
// If optimizations are disabled, forcing inlining can lead to significant
// code bloat and high compile times. Don't use simdjson_really_inline for
// unoptimized builds.
#define simdjson_inline inline
#else
// Force inlining for most simdjson functions.
#define simdjson_inline simdjson_really_inline
#endif
#if SIMDJSON_VISUAL_STUDIO
/**
* Windows users need to do some extra work when building
* or using a dynamic library (DLL). When building, we need
@@ -266,11 +278,30 @@ namespace std {
/// If EXPR is an error, returns it.
#define SIMDJSON_TRY(EXPR) { auto _err = (EXPR); if (_err) { return _err; } }
// Unless the programmer has already set SIMDJSON_DEVELOPMENT_CHECKS,
// we want to set it under debug builds. We detect a debug build
// under Visual Studio when the _DEBUG macro is set. Under the other
// compilers, we use the fact that they define __OPTIMIZE__ whenever
// they allow optimizations.
// It is possible that this could miss some cases where SIMDJSON_DEVELOPMENT_CHECKS
// is helpful, but the programmer can set the macro SIMDJSON_DEVELOPMENT_CHECKS.
// It could also wrongly set SIMDJSON_DEVELOPMENT_CHECKS (e.g., if the programmer
// sets _DEBUG in a release build under Visual Studio, or if some compiler fails to
// set the __OPTIMIZE__ macro).
#ifndef SIMDJSON_DEVELOPMENT_CHECKS
#ifndef NDEBUG
#define SIMDJSON_DEVELOPMENT_CHECKS
#endif
#endif
#ifdef _MSC_VER
// Visual Studio seems to set _DEBUG for debug builds.
#ifdef _DEBUG
#define SIMDJSON_DEVELOPMENT_CHECKS 1
#endif // _DEBUG
#else // _MSC_VER
// All other compilers appear to set __OPTIMIZE__ to a positive integer
// when the compiler is optimizing.
#ifndef __OPTIMIZE__
#define SIMDJSON_DEVELOPMENT_CHECKS 1
#endif // __OPTIMIZE__
#endif // _MSC_VER
#endif // SIMDJSON_DEVELOPMENT_CHECKS
// The SIMDJSON_CHECK_EOF macro is a feature flag for the "don't require padding"
// feature.
@@ -291,4 +322,15 @@ namespace std {
# define simdjson_fallthrough do {} while (0) /* fallthrough */
#endif // simdjson_fallthrough
#if SIMDJSON_DEVELOPMENT_CHECKS
#define SIMDJSON_DEVELOPMENT_ASSERT(expr) do { assert ((expr)); } while (0)
#else
#define SIMDJSON_DEVELOPMENT_ASSERT(expr) do { } while (0)
#endif
#ifndef SIMDJSON_UTF8VALIDATION
#define SIMDJSON_UTF8VALIDATION 1
#endif
#endif // SIMDJSON_COMMON_DEFS_H
+12 -6
View File
@@ -12,11 +12,11 @@ namespace simdjson {
//
// simdjson_result<dom::array> inline implementation
//
simdjson_really_inline simdjson_result<dom::array>::simdjson_result() noexcept
simdjson_inline simdjson_result<dom::array>::simdjson_result() noexcept
: internal::simdjson_result_base<dom::array>() {}
simdjson_really_inline simdjson_result<dom::array>::simdjson_result(dom::array value) noexcept
simdjson_inline simdjson_result<dom::array>::simdjson_result(dom::array value) noexcept
: internal::simdjson_result_base<dom::array>(std::forward<dom::array>(value)) {}
simdjson_really_inline simdjson_result<dom::array>::simdjson_result(error_code error) noexcept
simdjson_inline simdjson_result<dom::array>::simdjson_result(error_code error) noexcept
: internal::simdjson_result_base<dom::array>(error) {}
#if SIMDJSON_EXCEPTIONS
@@ -50,21 +50,26 @@ namespace dom {
//
// array inline implementation
//
simdjson_really_inline array::array() noexcept : tape{} {}
simdjson_really_inline array::array(const internal::tape_ref &_tape) noexcept : tape{_tape} {}
simdjson_inline array::array() noexcept : tape{} {}
simdjson_inline array::array(const internal::tape_ref &_tape) noexcept : tape{_tape} {}
inline array::iterator array::begin() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
return internal::tape_ref(tape.doc, tape.json_index + 1);
}
inline array::iterator array::end() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
return internal::tape_ref(tape.doc, tape.after_element() - 1);
}
inline size_t array::size() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
return tape.scope_count();
}
inline size_t array::number_of_slots() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
return tape.matching_brace_index() - tape.json_index;
}
inline simdjson_result<element> array::at_pointer(std::string_view json_pointer) const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
if(json_pointer.empty()) { // an empty string means that we return the current node
return element(this->tape); // copy the current node
} else if(json_pointer[0] != '/') { // otherwise there is an error
@@ -105,6 +110,7 @@ inline simdjson_result<element> array::at_pointer(std::string_view json_pointer)
}
inline simdjson_result<element> array::at(size_t index) const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
size_t i=0;
for (auto element : *this) {
if (i == index) { return element; }
@@ -116,7 +122,7 @@ inline simdjson_result<element> array::at(size_t index) const noexcept {
//
// array::iterator inline implementation
//
simdjson_really_inline array::iterator::iterator(const internal::tape_ref &_tape) noexcept : tape{_tape} { }
simdjson_inline array::iterator::iterator(const internal::tape_ref &_tape) noexcept : tape{_tape} { }
inline element array::iterator::operator*() const noexcept {
return element(tape);
}
+6 -6
View File
@@ -22,7 +22,7 @@ class element;
class array {
public:
/** Create a new, invalid array */
simdjson_really_inline array() noexcept;
simdjson_inline array() noexcept;
class iterator {
public:
@@ -62,7 +62,7 @@ public:
iterator(const iterator&) noexcept = default;
iterator& operator=(const iterator&) noexcept = default;
private:
simdjson_really_inline iterator(const internal::tape_ref &tape) noexcept;
simdjson_inline iterator(const internal::tape_ref &tape) noexcept;
internal::tape_ref tape;
friend class array;
};
@@ -133,7 +133,7 @@ public:
inline simdjson_result<element> at(size_t index) const noexcept;
private:
simdjson_really_inline array(const internal::tape_ref &tape) noexcept;
simdjson_inline array(const internal::tape_ref &tape) noexcept;
internal::tape_ref tape;
friend class element;
friend struct simdjson_result<element>;
@@ -148,9 +148,9 @@ private:
template<>
struct simdjson_result<dom::array> : public internal::simdjson_result_base<dom::array> {
public:
simdjson_really_inline simdjson_result() noexcept; ///< @private
simdjson_really_inline simdjson_result(dom::array value) noexcept; ///< @private
simdjson_really_inline simdjson_result(error_code error) noexcept; ///< @private
simdjson_inline simdjson_result() noexcept; ///< @private
simdjson_inline simdjson_result(dom::array value) noexcept; ///< @private
simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
inline simdjson_result<dom::element> at_pointer(std::string_view json_pointer) const noexcept;
inline simdjson_result<dom::element> at(size_t index) const noexcept;
+19 -19
View File
@@ -81,7 +81,7 @@ inline void stage1_worker::run(document_stream * ds, dom::parser * stage1, size_
}
#endif
simdjson_really_inline document_stream::document_stream(
simdjson_inline document_stream::document_stream(
dom::parser &_parser,
const uint8_t *_buf,
size_t _len,
@@ -103,7 +103,7 @@ simdjson_really_inline document_stream::document_stream(
#endif
}
simdjson_really_inline document_stream::document_stream() noexcept
simdjson_inline document_stream::document_stream() noexcept
: parser{nullptr},
buf{nullptr},
len{0},
@@ -115,31 +115,31 @@ simdjson_really_inline document_stream::document_stream() noexcept
{
}
simdjson_really_inline document_stream::~document_stream() noexcept {
simdjson_inline document_stream::~document_stream() noexcept {
#ifdef SIMDJSON_THREADS_ENABLED
worker.reset();
#endif
}
simdjson_really_inline document_stream::iterator::iterator() noexcept
simdjson_inline document_stream::iterator::iterator() noexcept
: stream{nullptr}, finished{true} {
}
simdjson_really_inline document_stream::iterator document_stream::begin() noexcept {
simdjson_inline document_stream::iterator document_stream::begin() noexcept {
start();
// If there are no documents, we're finished.
return iterator(this, error == EMPTY);
}
simdjson_really_inline document_stream::iterator document_stream::end() noexcept {
simdjson_inline document_stream::iterator document_stream::end() noexcept {
return iterator(this, true);
}
simdjson_really_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
simdjson_inline document_stream::iterator::iterator(document_stream* _stream, bool is_end) noexcept
: stream{_stream}, finished{is_end} {
}
simdjson_really_inline document_stream::iterator::reference document_stream::iterator::operator*() noexcept {
simdjson_inline document_stream::iterator::reference document_stream::iterator::operator*() noexcept {
// Note that in case of error, we do not yet mark
// the iterator as "finished": this detection is done
// in the operator++ function since it is possible
@@ -149,7 +149,7 @@ simdjson_really_inline document_stream::iterator::reference document_stream::ite
return stream->parser->doc.root();
}
simdjson_really_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
simdjson_inline document_stream::iterator& document_stream::iterator::operator++() noexcept {
// If there is an error, then we want the iterator
// to be finished, no matter what. (E.g., we do not
// keep generating documents with errors, or go beyond
@@ -176,7 +176,7 @@ simdjson_really_inline document_stream::iterator& document_stream::iterator::ope
return *this;
}
simdjson_really_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
simdjson_inline bool document_stream::iterator::operator!=(const document_stream::iterator &other) const noexcept {
return finished != other.finished;
}
@@ -207,11 +207,11 @@ inline void document_stream::start() noexcept {
next();
}
simdjson_really_inline size_t document_stream::iterator::current_index() const noexcept {
simdjson_inline size_t document_stream::iterator::current_index() const noexcept {
return stream->doc_index;
}
simdjson_really_inline std::string_view document_stream::iterator::source() const noexcept {
simdjson_inline std::string_view document_stream::iterator::source() const noexcept {
const char* start = reinterpret_cast<const char*>(stream->buf) + current_index();
bool object_or_array = ((*start == '[') || (*start == '{'));
if(object_or_array) {
@@ -304,32 +304,32 @@ inline void document_stream::start_stage1_thread() noexcept {
} // namespace dom
simdjson_really_inline simdjson_result<dom::document_stream>::simdjson_result() noexcept
simdjson_inline simdjson_result<dom::document_stream>::simdjson_result() noexcept
: simdjson_result_base() {
}
simdjson_really_inline simdjson_result<dom::document_stream>::simdjson_result(error_code error) noexcept
simdjson_inline simdjson_result<dom::document_stream>::simdjson_result(error_code error) noexcept
: simdjson_result_base(error) {
}
simdjson_really_inline simdjson_result<dom::document_stream>::simdjson_result(dom::document_stream &&value) noexcept
simdjson_inline simdjson_result<dom::document_stream>::simdjson_result(dom::document_stream &&value) noexcept
: simdjson_result_base(std::forward<dom::document_stream>(value)) {
}
#if SIMDJSON_EXCEPTIONS
simdjson_really_inline dom::document_stream::iterator simdjson_result<dom::document_stream>::begin() noexcept(false) {
simdjson_inline dom::document_stream::iterator simdjson_result<dom::document_stream>::begin() noexcept(false) {
if (error()) { throw simdjson_error(error()); }
return first.begin();
}
simdjson_really_inline dom::document_stream::iterator simdjson_result<dom::document_stream>::end() noexcept(false) {
simdjson_inline dom::document_stream::iterator simdjson_result<dom::document_stream>::end() noexcept(false) {
if (error()) { throw simdjson_error(error()); }
return first.end();
}
#else // SIMDJSON_EXCEPTIONS
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
simdjson_really_inline dom::document_stream::iterator simdjson_result<dom::document_stream>::begin() noexcept {
simdjson_inline dom::document_stream::iterator simdjson_result<dom::document_stream>::begin() noexcept {
first.error = error();
return first.begin();
}
simdjson_really_inline dom::document_stream::iterator simdjson_result<dom::document_stream>::end() noexcept {
simdjson_inline dom::document_stream::iterator simdjson_result<dom::document_stream>::end() noexcept {
first.error = error();
return first.end();
}
+20 -20
View File
@@ -80,13 +80,13 @@ public:
* error = parser.parse_many(json).get(docs);
* ```
*/
simdjson_really_inline document_stream() noexcept;
simdjson_inline document_stream() noexcept;
/** Move one document_stream to another. */
simdjson_really_inline document_stream(document_stream &&other) noexcept = default;
simdjson_inline document_stream(document_stream &&other) noexcept = default;
/** Move one document_stream to another. */
simdjson_really_inline document_stream &operator=(document_stream &&other) noexcept = default;
simdjson_inline document_stream &operator=(document_stream &&other) noexcept = default;
simdjson_really_inline ~document_stream() noexcept;
simdjson_inline ~document_stream() noexcept;
/**
* Returns the input size in bytes.
*/
@@ -125,11 +125,11 @@ public:
/**
* Default constructor.
*/
simdjson_really_inline iterator() noexcept;
simdjson_inline iterator() noexcept;
/**
* Get the current document (or error).
*/
simdjson_really_inline reference operator*() noexcept;
simdjson_inline reference operator*() noexcept;
/**
* Advance to the next document (prefix).
*/
@@ -138,7 +138,7 @@ public:
* Check if we're at the end yet.
* @param other the end iterator to compare to.
*/
simdjson_really_inline bool operator!=(const iterator &other) const noexcept;
simdjson_inline bool operator!=(const iterator &other) const noexcept;
/**
* @private
*
@@ -154,7 +154,7 @@ public:
* may change in future versions of simdjson: we find the API somewhat
* awkward and we would like to offer something friendlier.
*/
simdjson_really_inline size_t current_index() const noexcept;
simdjson_inline size_t current_index() const noexcept;
/**
* @private
*
@@ -174,10 +174,10 @@ public:
* may change in future versions of simdjson: we find the API somewhat
* awkward and we would like to offer something friendlier.
*/
simdjson_really_inline std::string_view source() const noexcept;
simdjson_inline std::string_view source() const noexcept;
private:
simdjson_really_inline iterator(document_stream *s, bool finished) noexcept;
simdjson_inline iterator(document_stream *s, bool finished) noexcept;
/** The document_stream we're iterating through. */
document_stream* stream;
/** Whether we're finished or not. */
@@ -188,11 +188,11 @@ public:
/**
* Start iterating the documents in the stream.
*/
simdjson_really_inline iterator begin() noexcept;
simdjson_inline iterator begin() noexcept;
/**
* The end of the stream, for iterator comparison purposes.
*/
simdjson_really_inline iterator end() noexcept;
simdjson_inline iterator end() noexcept;
private:
@@ -208,7 +208,7 @@ private:
* @param len is the length of the raw byte buffer in bytes
* @param batch_size is the size of the windows (must be strictly greater or equal to the largest JSON document)
*/
simdjson_really_inline document_stream(
simdjson_inline document_stream(
dom::parser &parser,
const uint8_t *buf,
size_t len,
@@ -302,19 +302,19 @@ private:
template<>
struct simdjson_result<dom::document_stream> : public internal::simdjson_result_base<dom::document_stream> {
public:
simdjson_really_inline simdjson_result() noexcept; ///< @private
simdjson_really_inline simdjson_result(error_code error) noexcept; ///< @private
simdjson_really_inline simdjson_result(dom::document_stream &&value) noexcept; ///< @private
simdjson_inline simdjson_result() noexcept; ///< @private
simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
simdjson_inline simdjson_result(dom::document_stream &&value) noexcept; ///< @private
#if SIMDJSON_EXCEPTIONS
simdjson_really_inline dom::document_stream::iterator begin() noexcept(false);
simdjson_really_inline dom::document_stream::iterator end() noexcept(false);
simdjson_inline dom::document_stream::iterator begin() noexcept(false);
simdjson_inline dom::document_stream::iterator end() noexcept(false);
#else // SIMDJSON_EXCEPTIONS
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
[[deprecated("parse_many() and load_many() may return errors. Use document_stream stream; error = parser.parse_many().get(doc); instead.")]]
simdjson_really_inline dom::document_stream::iterator begin() noexcept;
simdjson_inline dom::document_stream::iterator begin() noexcept;
[[deprecated("parse_many() and load_many() may return errors. Use document_stream stream; error = parser.parse_many().get(doc); instead.")]]
simdjson_really_inline dom::document_stream::iterator end() noexcept;
simdjson_inline dom::document_stream::iterator end() noexcept;
#endif // SIMDJSON_DISABLE_DEPRECATED_API
#endif // SIMDJSON_EXCEPTIONS
}; // struct simdjson_result<dom::document_stream>
+58 -46
View File
@@ -12,11 +12,11 @@ namespace simdjson {
//
// simdjson_result<dom::element> inline implementation
//
simdjson_really_inline simdjson_result<dom::element>::simdjson_result() noexcept
simdjson_inline simdjson_result<dom::element>::simdjson_result() noexcept
: internal::simdjson_result_base<dom::element>() {}
simdjson_really_inline simdjson_result<dom::element>::simdjson_result(dom::element &&value) noexcept
simdjson_inline simdjson_result<dom::element>::simdjson_result(dom::element &&value) noexcept
: internal::simdjson_result_base<dom::element>(std::forward<dom::element>(value)) {}
simdjson_really_inline simdjson_result<dom::element>::simdjson_result(error_code error) noexcept
simdjson_inline simdjson_result<dom::element>::simdjson_result(error_code error) noexcept
: internal::simdjson_result_base<dom::element>(error) {}
inline simdjson_result<dom::element_type> simdjson_result<dom::element>::type() const noexcept {
if (error()) { return error(); }
@@ -24,101 +24,101 @@ inline simdjson_result<dom::element_type> simdjson_result<dom::element>::type()
}
template<typename T>
simdjson_really_inline bool simdjson_result<dom::element>::is() const noexcept {
simdjson_inline bool simdjson_result<dom::element>::is() const noexcept {
return !error() && first.is<T>();
}
template<typename T>
simdjson_really_inline simdjson_result<T> simdjson_result<dom::element>::get() const noexcept {
simdjson_inline simdjson_result<T> simdjson_result<dom::element>::get() const noexcept {
if (error()) { return error(); }
return first.get<T>();
}
template<typename T>
simdjson_warn_unused simdjson_really_inline error_code simdjson_result<dom::element>::get(T &value) const noexcept {
simdjson_warn_unused simdjson_inline error_code simdjson_result<dom::element>::get(T &value) const noexcept {
if (error()) { return error(); }
return first.get<T>(value);
}
simdjson_really_inline simdjson_result<dom::array> simdjson_result<dom::element>::get_array() const noexcept {
simdjson_inline simdjson_result<dom::array> simdjson_result<dom::element>::get_array() const noexcept {
if (error()) { return error(); }
return first.get_array();
}
simdjson_really_inline simdjson_result<dom::object> simdjson_result<dom::element>::get_object() const noexcept {
simdjson_inline simdjson_result<dom::object> simdjson_result<dom::element>::get_object() const noexcept {
if (error()) { return error(); }
return first.get_object();
}
simdjson_really_inline simdjson_result<const char *> simdjson_result<dom::element>::get_c_str() const noexcept {
simdjson_inline simdjson_result<const char *> simdjson_result<dom::element>::get_c_str() const noexcept {
if (error()) { return error(); }
return first.get_c_str();
}
simdjson_really_inline simdjson_result<size_t> simdjson_result<dom::element>::get_string_length() const noexcept {
simdjson_inline simdjson_result<size_t> simdjson_result<dom::element>::get_string_length() const noexcept {
if (error()) { return error(); }
return first.get_string_length();
}
simdjson_really_inline simdjson_result<std::string_view> simdjson_result<dom::element>::get_string() const noexcept {
simdjson_inline simdjson_result<std::string_view> simdjson_result<dom::element>::get_string() const noexcept {
if (error()) { return error(); }
return first.get_string();
}
simdjson_really_inline simdjson_result<int64_t> simdjson_result<dom::element>::get_int64() const noexcept {
simdjson_inline simdjson_result<int64_t> simdjson_result<dom::element>::get_int64() const noexcept {
if (error()) { return error(); }
return first.get_int64();
}
simdjson_really_inline simdjson_result<uint64_t> simdjson_result<dom::element>::get_uint64() const noexcept {
simdjson_inline simdjson_result<uint64_t> simdjson_result<dom::element>::get_uint64() const noexcept {
if (error()) { return error(); }
return first.get_uint64();
}
simdjson_really_inline simdjson_result<double> simdjson_result<dom::element>::get_double() const noexcept {
simdjson_inline simdjson_result<double> simdjson_result<dom::element>::get_double() const noexcept {
if (error()) { return error(); }
return first.get_double();
}
simdjson_really_inline simdjson_result<bool> simdjson_result<dom::element>::get_bool() const noexcept {
simdjson_inline simdjson_result<bool> simdjson_result<dom::element>::get_bool() const noexcept {
if (error()) { return error(); }
return first.get_bool();
}
simdjson_really_inline bool simdjson_result<dom::element>::is_array() const noexcept {
simdjson_inline bool simdjson_result<dom::element>::is_array() const noexcept {
return !error() && first.is_array();
}
simdjson_really_inline bool simdjson_result<dom::element>::is_object() const noexcept {
simdjson_inline bool simdjson_result<dom::element>::is_object() const noexcept {
return !error() && first.is_object();
}
simdjson_really_inline bool simdjson_result<dom::element>::is_string() const noexcept {
simdjson_inline bool simdjson_result<dom::element>::is_string() const noexcept {
return !error() && first.is_string();
}
simdjson_really_inline bool simdjson_result<dom::element>::is_int64() const noexcept {
simdjson_inline bool simdjson_result<dom::element>::is_int64() const noexcept {
return !error() && first.is_int64();
}
simdjson_really_inline bool simdjson_result<dom::element>::is_uint64() const noexcept {
simdjson_inline bool simdjson_result<dom::element>::is_uint64() const noexcept {
return !error() && first.is_uint64();
}
simdjson_really_inline bool simdjson_result<dom::element>::is_double() const noexcept {
simdjson_inline bool simdjson_result<dom::element>::is_double() const noexcept {
return !error() && first.is_double();
}
simdjson_really_inline bool simdjson_result<dom::element>::is_number() const noexcept {
simdjson_inline bool simdjson_result<dom::element>::is_number() const noexcept {
return !error() && first.is_number();
}
simdjson_really_inline bool simdjson_result<dom::element>::is_bool() const noexcept {
simdjson_inline bool simdjson_result<dom::element>::is_bool() const noexcept {
return !error() && first.is_bool();
}
simdjson_really_inline bool simdjson_result<dom::element>::is_null() const noexcept {
simdjson_inline bool simdjson_result<dom::element>::is_null() const noexcept {
return !error() && first.is_null();
}
simdjson_really_inline simdjson_result<dom::element> simdjson_result<dom::element>::operator[](std::string_view key) const noexcept {
simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::operator[](std::string_view key) const noexcept {
if (error()) { return error(); }
return first[key];
}
simdjson_really_inline simdjson_result<dom::element> simdjson_result<dom::element>::operator[](const char *key) const noexcept {
simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::operator[](const char *key) const noexcept {
if (error()) { return error(); }
return first[key];
}
simdjson_really_inline simdjson_result<dom::element> simdjson_result<dom::element>::at_pointer(const std::string_view json_pointer) const noexcept {
simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at_pointer(const std::string_view json_pointer) const noexcept {
if (error()) { return error(); }
return first.at_pointer(json_pointer);
}
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
[[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
simdjson_really_inline simdjson_result<dom::element> simdjson_result<dom::element>::at(const std::string_view json_pointer) const noexcept {
simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at(const std::string_view json_pointer) const noexcept {
SIMDJSON_PUSH_DISABLE_WARNINGS
SIMDJSON_DISABLE_DEPRECATED_WARNING
if (error()) { return error(); }
@@ -126,51 +126,51 @@ SIMDJSON_DISABLE_DEPRECATED_WARNING
SIMDJSON_POP_DISABLE_WARNINGS
}
#endif // SIMDJSON_DISABLE_DEPRECATED_API
simdjson_really_inline simdjson_result<dom::element> simdjson_result<dom::element>::at(size_t index) const noexcept {
simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at(size_t index) const noexcept {
if (error()) { return error(); }
return first.at(index);
}
simdjson_really_inline simdjson_result<dom::element> simdjson_result<dom::element>::at_key(std::string_view key) const noexcept {
simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at_key(std::string_view key) const noexcept {
if (error()) { return error(); }
return first.at_key(key);
}
simdjson_really_inline simdjson_result<dom::element> simdjson_result<dom::element>::at_key_case_insensitive(std::string_view key) const noexcept {
simdjson_inline simdjson_result<dom::element> simdjson_result<dom::element>::at_key_case_insensitive(std::string_view key) const noexcept {
if (error()) { return error(); }
return first.at_key_case_insensitive(key);
}
#if SIMDJSON_EXCEPTIONS
simdjson_really_inline simdjson_result<dom::element>::operator bool() const noexcept(false) {
simdjson_inline simdjson_result<dom::element>::operator bool() const noexcept(false) {
return get<bool>();
}
simdjson_really_inline simdjson_result<dom::element>::operator const char *() const noexcept(false) {
simdjson_inline simdjson_result<dom::element>::operator const char *() const noexcept(false) {
return get<const char *>();
}
simdjson_really_inline simdjson_result<dom::element>::operator std::string_view() const noexcept(false) {
simdjson_inline simdjson_result<dom::element>::operator std::string_view() const noexcept(false) {
return get<std::string_view>();
}
simdjson_really_inline simdjson_result<dom::element>::operator uint64_t() const noexcept(false) {
simdjson_inline simdjson_result<dom::element>::operator uint64_t() const noexcept(false) {
return get<uint64_t>();
}
simdjson_really_inline simdjson_result<dom::element>::operator int64_t() const noexcept(false) {
simdjson_inline simdjson_result<dom::element>::operator int64_t() const noexcept(false) {
return get<int64_t>();
}
simdjson_really_inline simdjson_result<dom::element>::operator double() const noexcept(false) {
simdjson_inline simdjson_result<dom::element>::operator double() const noexcept(false) {
return get<double>();
}
simdjson_really_inline simdjson_result<dom::element>::operator dom::array() const noexcept(false) {
simdjson_inline simdjson_result<dom::element>::operator dom::array() const noexcept(false) {
return get<dom::array>();
}
simdjson_really_inline simdjson_result<dom::element>::operator dom::object() const noexcept(false) {
simdjson_inline simdjson_result<dom::element>::operator dom::object() const noexcept(false) {
return get<dom::object>();
}
simdjson_really_inline dom::array::iterator simdjson_result<dom::element>::begin() const noexcept(false) {
simdjson_inline dom::array::iterator simdjson_result<dom::element>::begin() const noexcept(false) {
if (error()) { throw simdjson_error(error()); }
return first.begin();
}
simdjson_really_inline dom::array::iterator simdjson_result<dom::element>::end() const noexcept(false) {
simdjson_inline dom::array::iterator simdjson_result<dom::element>::end() const noexcept(false) {
if (error()) { throw simdjson_error(error()); }
return first.end();
}
@@ -182,15 +182,17 @@ namespace dom {
//
// element inline implementation
//
simdjson_really_inline element::element() noexcept : tape{} {}
simdjson_really_inline element::element(const internal::tape_ref &_tape) noexcept : tape{_tape} { }
simdjson_inline element::element() noexcept : tape{} {}
simdjson_inline element::element(const internal::tape_ref &_tape) noexcept : tape{_tape} { }
inline element_type element::type() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
auto tape_type = tape.tape_ref_type();
return tape_type == internal::tape_type::FALSE_VALUE ? element_type::BOOL : static_cast<element_type>(tape_type);
}
inline simdjson_result<bool> element::get_bool() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
if(tape.is_true()) {
return true;
} else if(tape.is_false()) {
@@ -199,6 +201,7 @@ inline simdjson_result<bool> element::get_bool() const noexcept {
return INCORRECT_TYPE;
}
inline simdjson_result<const char *> element::get_c_str() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
switch (tape.tape_ref_type()) {
case internal::tape_type::STRING: {
return tape.get_c_str();
@@ -208,6 +211,7 @@ inline simdjson_result<const char *> element::get_c_str() const noexcept {
}
}
inline simdjson_result<size_t> element::get_string_length() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
switch (tape.tape_ref_type()) {
case internal::tape_type::STRING: {
return tape.get_string_length();
@@ -217,6 +221,7 @@ inline simdjson_result<size_t> element::get_string_length() const noexcept {
}
}
inline simdjson_result<std::string_view> element::get_string() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
switch (tape.tape_ref_type()) {
case internal::tape_type::STRING:
return tape.get_string_view();
@@ -225,6 +230,7 @@ inline simdjson_result<std::string_view> element::get_string() const noexcept {
}
}
inline simdjson_result<uint64_t> element::get_uint64() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
if(simdjson_unlikely(!tape.is_uint64())) { // branch rarely taken
if(tape.is_int64()) {
int64_t result = tape.next_tape_value<int64_t>();
@@ -238,6 +244,7 @@ inline simdjson_result<uint64_t> element::get_uint64() const noexcept {
return tape.next_tape_value<int64_t>();
}
inline simdjson_result<int64_t> element::get_int64() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
if(simdjson_unlikely(!tape.is_int64())) { // branch rarely taken
if(tape.is_uint64()) {
uint64_t result = tape.next_tape_value<uint64_t>();
@@ -252,6 +259,7 @@ inline simdjson_result<int64_t> element::get_int64() const noexcept {
return tape.next_tape_value<int64_t>();
}
inline simdjson_result<double> element::get_double() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
// Performance considerations:
// 1. Querying tape_ref_type() implies doing a shift, it is fast to just do a straight
// comparison.
@@ -273,6 +281,7 @@ inline simdjson_result<double> element::get_double() const noexcept {
return tape.next_tape_value<double>();
}
inline simdjson_result<array> element::get_array() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
switch (tape.tape_ref_type()) {
case internal::tape_type::START_ARRAY:
return array(tape);
@@ -281,6 +290,7 @@ inline simdjson_result<array> element::get_array() const noexcept {
}
}
inline simdjson_result<object> element::get_object() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
switch (tape.tape_ref_type()) {
case internal::tape_type::START_OBJECT:
return object(tape);
@@ -290,12 +300,12 @@ inline simdjson_result<object> element::get_object() const noexcept {
}
template<typename T>
simdjson_warn_unused simdjson_really_inline error_code element::get(T &value) const noexcept {
simdjson_warn_unused simdjson_inline error_code element::get(T &value) const noexcept {
return get<T>().get(value);
}
// An element-specific version prevents recursion with simdjson_result::get<element>(value)
template<>
simdjson_warn_unused simdjson_really_inline error_code element::get<element>(element &value) const noexcept {
simdjson_warn_unused simdjson_inline error_code element::get<element>(element &value) const noexcept {
value = element(tape);
return SUCCESS;
}
@@ -305,7 +315,7 @@ inline void element::tie(T &value, error_code &error) && noexcept {
}
template<typename T>
simdjson_really_inline bool element::is() const noexcept {
simdjson_inline bool element::is() const noexcept {
auto result = get<T>();
return !result.error();
}
@@ -360,6 +370,7 @@ inline simdjson_result<element> element::operator[](const char *key) const noexc
}
inline simdjson_result<element> element::at_pointer(std::string_view json_pointer) const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
switch (tape.tape_ref_type()) {
case internal::tape_type::START_OBJECT:
return object(tape).at_pointer(json_pointer);
@@ -395,6 +406,7 @@ inline simdjson_result<element> element::at_key_case_insensitive(std::string_vie
}
inline bool element::dump_raw_tape(std::ostream &out) const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
return tape.doc->dump_raw_tape(out);
}
+47 -47
View File
@@ -40,10 +40,10 @@ enum class element_type {
class element {
public:
/** Create a new, invalid element. */
simdjson_really_inline element() noexcept;
simdjson_inline element() noexcept;
/** The type of this element. */
simdjson_really_inline element_type type() const noexcept;
simdjson_inline element_type type() const noexcept;
/**
* Cast this element to an array.
@@ -195,7 +195,7 @@ public:
* @tparam T bool, double, uint64_t, int64_t, std::string_view, const char *, dom::array, dom::object
*/
template<typename T>
simdjson_really_inline bool is() const noexcept;
simdjson_inline bool is() const noexcept;
/**
* Get the value as the provided type (T).
@@ -240,7 +240,7 @@ public:
* @returns The error that occurred, or SUCCESS if there was no error.
*/
template<typename T>
simdjson_warn_unused simdjson_really_inline error_code get(T &value) const noexcept;
simdjson_warn_unused simdjson_inline error_code get(T &value) const noexcept;
/**
* Get the value as the provided type (T), setting error if it's not the given type.
@@ -464,7 +464,7 @@ public:
inline bool dump_raw_tape(std::ostream &out) const noexcept;
private:
simdjson_really_inline element(const internal::tape_ref &tape) noexcept;
simdjson_inline element(const internal::tape_ref &tape) noexcept;
internal::tape_ref tape;
friend class document;
friend class object;
@@ -481,59 +481,59 @@ private:
template<>
struct simdjson_result<dom::element> : public internal::simdjson_result_base<dom::element> {
public:
simdjson_really_inline simdjson_result() noexcept; ///< @private
simdjson_really_inline simdjson_result(dom::element &&value) noexcept; ///< @private
simdjson_really_inline simdjson_result(error_code error) noexcept; ///< @private
simdjson_inline simdjson_result() noexcept; ///< @private
simdjson_inline simdjson_result(dom::element &&value) noexcept; ///< @private
simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
simdjson_really_inline simdjson_result<dom::element_type> type() const noexcept;
simdjson_inline simdjson_result<dom::element_type> type() const noexcept;
template<typename T>
simdjson_really_inline bool is() const noexcept;
simdjson_inline bool is() const noexcept;
template<typename T>
simdjson_really_inline simdjson_result<T> get() const noexcept;
simdjson_inline simdjson_result<T> get() const noexcept;
template<typename T>
simdjson_warn_unused simdjson_really_inline error_code get(T &value) const noexcept;
simdjson_warn_unused simdjson_inline error_code get(T &value) const noexcept;
simdjson_really_inline simdjson_result<dom::array> get_array() const noexcept;
simdjson_really_inline simdjson_result<dom::object> get_object() const noexcept;
simdjson_really_inline simdjson_result<const char *> get_c_str() const noexcept;
simdjson_really_inline simdjson_result<size_t> get_string_length() const noexcept;
simdjson_really_inline simdjson_result<std::string_view> get_string() const noexcept;
simdjson_really_inline simdjson_result<int64_t> get_int64() const noexcept;
simdjson_really_inline simdjson_result<uint64_t> get_uint64() const noexcept;
simdjson_really_inline simdjson_result<double> get_double() const noexcept;
simdjson_really_inline simdjson_result<bool> get_bool() const noexcept;
simdjson_inline simdjson_result<dom::array> get_array() const noexcept;
simdjson_inline simdjson_result<dom::object> get_object() const noexcept;
simdjson_inline simdjson_result<const char *> get_c_str() const noexcept;
simdjson_inline simdjson_result<size_t> get_string_length() const noexcept;
simdjson_inline simdjson_result<std::string_view> get_string() const noexcept;
simdjson_inline simdjson_result<int64_t> get_int64() const noexcept;
simdjson_inline simdjson_result<uint64_t> get_uint64() const noexcept;
simdjson_inline simdjson_result<double> get_double() const noexcept;
simdjson_inline simdjson_result<bool> get_bool() const noexcept;
simdjson_really_inline bool is_array() const noexcept;
simdjson_really_inline bool is_object() const noexcept;
simdjson_really_inline bool is_string() const noexcept;
simdjson_really_inline bool is_int64() const noexcept;
simdjson_really_inline bool is_uint64() const noexcept;
simdjson_really_inline bool is_double() const noexcept;
simdjson_really_inline bool is_number() const noexcept;
simdjson_really_inline bool is_bool() const noexcept;
simdjson_really_inline bool is_null() const noexcept;
simdjson_inline bool is_array() const noexcept;
simdjson_inline bool is_object() const noexcept;
simdjson_inline bool is_string() const noexcept;
simdjson_inline bool is_int64() const noexcept;
simdjson_inline bool is_uint64() const noexcept;
simdjson_inline bool is_double() const noexcept;
simdjson_inline bool is_number() const noexcept;
simdjson_inline bool is_bool() const noexcept;
simdjson_inline bool is_null() const noexcept;
simdjson_really_inline simdjson_result<dom::element> operator[](std::string_view key) const noexcept;
simdjson_really_inline simdjson_result<dom::element> operator[](const char *key) const noexcept;
simdjson_really_inline simdjson_result<dom::element> at_pointer(const std::string_view json_pointer) const noexcept;
simdjson_inline simdjson_result<dom::element> operator[](std::string_view key) const noexcept;
simdjson_inline simdjson_result<dom::element> operator[](const char *key) const noexcept;
simdjson_inline simdjson_result<dom::element> at_pointer(const std::string_view json_pointer) const noexcept;
[[deprecated("For standard compliance, use at_pointer instead, and prefix your pointers with a slash '/', see RFC6901 ")]]
simdjson_really_inline simdjson_result<dom::element> at(const std::string_view json_pointer) const noexcept;
simdjson_really_inline simdjson_result<dom::element> at(size_t index) const noexcept;
simdjson_really_inline simdjson_result<dom::element> at_key(std::string_view key) const noexcept;
simdjson_really_inline simdjson_result<dom::element> at_key_case_insensitive(std::string_view key) const noexcept;
simdjson_inline simdjson_result<dom::element> at(const std::string_view json_pointer) const noexcept;
simdjson_inline simdjson_result<dom::element> at(size_t index) const noexcept;
simdjson_inline simdjson_result<dom::element> at_key(std::string_view key) const noexcept;
simdjson_inline simdjson_result<dom::element> at_key_case_insensitive(std::string_view key) const noexcept;
#if SIMDJSON_EXCEPTIONS
simdjson_really_inline operator bool() const noexcept(false);
simdjson_really_inline explicit operator const char*() const noexcept(false);
simdjson_really_inline operator std::string_view() const noexcept(false);
simdjson_really_inline operator uint64_t() const noexcept(false);
simdjson_really_inline operator int64_t() const noexcept(false);
simdjson_really_inline operator double() const noexcept(false);
simdjson_really_inline operator dom::array() const noexcept(false);
simdjson_really_inline operator dom::object() const noexcept(false);
simdjson_inline operator bool() const noexcept(false);
simdjson_inline explicit operator const char*() const noexcept(false);
simdjson_inline operator std::string_view() const noexcept(false);
simdjson_inline operator uint64_t() const noexcept(false);
simdjson_inline operator int64_t() const noexcept(false);
simdjson_inline operator double() const noexcept(false);
simdjson_inline operator dom::array() const noexcept(false);
simdjson_inline operator dom::object() const noexcept(false);
simdjson_really_inline dom::array::iterator begin() const noexcept(false);
simdjson_really_inline dom::array::iterator end() const noexcept(false);
simdjson_inline dom::array::iterator begin() const noexcept(false);
simdjson_inline dom::array::iterator end() const noexcept(false);
#endif // SIMDJSON_EXCEPTIONS
};
+10 -6
View File
@@ -12,11 +12,11 @@ namespace simdjson {
//
// simdjson_result<dom::object> inline implementation
//
simdjson_really_inline simdjson_result<dom::object>::simdjson_result() noexcept
simdjson_inline simdjson_result<dom::object>::simdjson_result() noexcept
: internal::simdjson_result_base<dom::object>() {}
simdjson_really_inline simdjson_result<dom::object>::simdjson_result(dom::object value) noexcept
simdjson_inline simdjson_result<dom::object>::simdjson_result(dom::object value) noexcept
: internal::simdjson_result_base<dom::object>(std::forward<dom::object>(value)) {}
simdjson_really_inline simdjson_result<dom::object>::simdjson_result(error_code error) noexcept
simdjson_inline simdjson_result<dom::object>::simdjson_result(error_code error) noexcept
: internal::simdjson_result_base<dom::object>(error) {}
inline simdjson_result<dom::element> simdjson_result<dom::object>::operator[](std::string_view key) const noexcept {
@@ -62,15 +62,18 @@ namespace dom {
//
// object inline implementation
//
simdjson_really_inline object::object() noexcept : tape{} {}
simdjson_really_inline object::object(const internal::tape_ref &_tape) noexcept : tape{_tape} { }
simdjson_inline object::object() noexcept : tape{} {}
simdjson_inline object::object(const internal::tape_ref &_tape) noexcept : tape{_tape} { }
inline object::iterator object::begin() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
return internal::tape_ref(tape.doc, tape.json_index + 1);
}
inline object::iterator object::end() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
return internal::tape_ref(tape.doc, tape.after_element() - 1);
}
inline size_t object::size() const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
return tape.scope_count();
}
@@ -81,6 +84,7 @@ inline simdjson_result<element> object::operator[](const char *key) const noexce
return at_key(key);
}
inline simdjson_result<element> object::at_pointer(std::string_view json_pointer) const noexcept {
SIMDJSON_DEVELOPMENT_ASSERT(tape.usable()); // https://github.com/simdjson/simdjson/issues/1914
if(json_pointer.empty()) { // an empty string means that we return the current node
return element(this->tape); // copy the current node
} else if(json_pointer[0] != '/') { // otherwise there is an error
@@ -149,7 +153,7 @@ inline simdjson_result<element> object::at_key_case_insensitive(std::string_view
//
// object::iterator inline implementation
//
simdjson_really_inline object::iterator::iterator(const internal::tape_ref &_tape) noexcept : tape{_tape} { }
simdjson_inline object::iterator::iterator(const internal::tape_ref &_tape) noexcept : tape{_tape} { }
inline const key_value_pair object::iterator::operator*() const noexcept {
return key_value_pair(key(), value());
}
+7 -7
View File
@@ -22,7 +22,7 @@ class key_value_pair;
class object {
public:
/** Create a new, invalid object */
simdjson_really_inline object() noexcept;
simdjson_inline object() noexcept;
class iterator {
public:
@@ -92,7 +92,7 @@ public:
iterator(const iterator&) noexcept = default;
iterator& operator=(const iterator&) noexcept = default;
private:
simdjson_really_inline iterator(const internal::tape_ref &tape) noexcept;
simdjson_inline iterator(const internal::tape_ref &tape) noexcept;
internal::tape_ref tape;
@@ -206,7 +206,7 @@ public:
inline simdjson_result<element> at_key_case_insensitive(std::string_view key) const noexcept;
private:
simdjson_really_inline object(const internal::tape_ref &tape) noexcept;
simdjson_inline object(const internal::tape_ref &tape) noexcept;
internal::tape_ref tape;
@@ -227,7 +227,7 @@ public:
element value;
private:
simdjson_really_inline key_value_pair(std::string_view _key, element _value) noexcept;
simdjson_inline key_value_pair(std::string_view _key, element _value) noexcept;
friend class object;
};
@@ -237,9 +237,9 @@ private:
template<>
struct simdjson_result<dom::object> : public internal::simdjson_result_base<dom::object> {
public:
simdjson_really_inline simdjson_result() noexcept; ///< @private
simdjson_really_inline simdjson_result(dom::object value) noexcept; ///< @private
simdjson_really_inline simdjson_result(error_code error) noexcept; ///< @private
simdjson_inline simdjson_result() noexcept; ///< @private
simdjson_inline simdjson_result(dom::object value) noexcept; ///< @private
simdjson_inline simdjson_result(error_code error) noexcept; ///< @private
inline simdjson_result<dom::element> operator[](std::string_view key) const noexcept;
inline simdjson_result<dom::element> operator[](const char *key) const noexcept;
+25 -16
View File
@@ -15,12 +15,12 @@ namespace dom {
//
// parser inline implementation
//
simdjson_really_inline parser::parser(size_t max_capacity) noexcept
simdjson_inline parser::parser(size_t max_capacity) noexcept
: _max_capacity{max_capacity},
loaded_bytes(nullptr) {
}
simdjson_really_inline parser::parser(parser &&other) noexcept = default;
simdjson_really_inline parser &parser::operator=(parser &&other) noexcept = default;
simdjson_inline parser::parser(parser &&other) noexcept = default;
simdjson_inline parser &parser::operator=(parser &&other) noexcept = default;
inline bool parser::is_valid() const noexcept { return valid; }
inline int parser::get_error_code() const noexcept { return error; }
@@ -42,11 +42,17 @@ inline simdjson_result<size_t> parser::read_file(const std::string &path) noexce
}
// Get the file size
if(std::fseek(fp, 0, SEEK_END) < 0) {
int ret;
#if SIMDJSON_VISUAL_STUDIO && !SIMDJSON_IS_32BITS
ret = _fseeki64(fp, 0, SEEK_END);
#else
ret = std::fseek(fp, 0, SEEK_END);
#endif // _WIN64
if(ret < 0) {
std::fclose(fp);
return IO_ERROR;
}
#if defined(SIMDJSON_VISUAL_STUDIO) && !SIMDJSON_IS_32BITS
#if SIMDJSON_VISUAL_STUDIO && !SIMDJSON_IS_32BITS
__int64 len = _ftelli64(fp);
if(len == -1L) {
std::fclose(fp);
@@ -118,13 +124,13 @@ inline simdjson_result<element> parser::parse_into_document(document& provided_d
return provided_doc.root();
}
simdjson_really_inline simdjson_result<element> parser::parse_into_document(document& provided_doc, const char *buf, size_t len, bool realloc_if_needed) & noexcept {
simdjson_inline simdjson_result<element> parser::parse_into_document(document& provided_doc, const char *buf, size_t len, bool realloc_if_needed) & noexcept {
return parse_into_document(provided_doc, reinterpret_cast<const uint8_t *>(buf), len, realloc_if_needed);
}
simdjson_really_inline simdjson_result<element> parser::parse_into_document(document& provided_doc, const std::string &s) & noexcept {
simdjson_inline simdjson_result<element> parser::parse_into_document(document& provided_doc, const std::string &s) & noexcept {
return parse_into_document(provided_doc, s.data(), s.length(), s.capacity() - s.length() < SIMDJSON_PADDING);
}
simdjson_really_inline simdjson_result<element> parser::parse_into_document(document& provided_doc, const padded_string &s) & noexcept {
simdjson_inline simdjson_result<element> parser::parse_into_document(document& provided_doc, const padded_string &s) & noexcept {
return parse_into_document(provided_doc, s.data(), s.length(), false);
}
@@ -133,15 +139,18 @@ inline simdjson_result<element> parser::parse(const uint8_t *buf, size_t len, bo
return parse_into_document(doc, buf, len, realloc_if_needed);
}
simdjson_really_inline simdjson_result<element> parser::parse(const char *buf, size_t len, bool realloc_if_needed) & noexcept {
simdjson_inline simdjson_result<element> parser::parse(const char *buf, size_t len, bool realloc_if_needed) & noexcept {
return parse(reinterpret_cast<const uint8_t *>(buf), len, realloc_if_needed);
}
simdjson_really_inline simdjson_result<element> parser::parse(const std::string &s) & noexcept {
simdjson_inline simdjson_result<element> parser::parse(const std::string &s) & noexcept {
return parse(s.data(), s.length(), s.capacity() - s.length() < SIMDJSON_PADDING);
}
simdjson_really_inline simdjson_result<element> parser::parse(const padded_string &s) & noexcept {
simdjson_inline simdjson_result<element> parser::parse(const padded_string &s) & noexcept {
return parse(s.data(), s.length(), false);
}
simdjson_inline simdjson_result<element> parser::parse(const padded_string_view &v) & noexcept {
return parse(v.data(), v.length(), false);
}
inline simdjson_result<document_stream> parser::parse_many(const uint8_t *buf, size_t len, size_t batch_size) noexcept {
if(batch_size < MINIMAL_BATCH_SIZE) { batch_size = MINIMAL_BATCH_SIZE; }
@@ -157,13 +166,13 @@ inline simdjson_result<document_stream> parser::parse_many(const padded_string &
return parse_many(s.data(), s.length(), batch_size);
}
simdjson_really_inline size_t parser::capacity() const noexcept {
simdjson_inline size_t parser::capacity() const noexcept {
return implementation ? implementation->capacity() : 0;
}
simdjson_really_inline size_t parser::max_capacity() const noexcept {
simdjson_inline size_t parser::max_capacity() const noexcept {
return _max_capacity;
}
simdjson_really_inline size_t parser::max_depth() const noexcept {
simdjson_inline size_t parser::max_depth() const noexcept {
return implementation ? implementation->max_depth() : DEFAULT_MAX_DEPTH;
}
@@ -216,8 +225,8 @@ inline error_code parser::ensure_capacity(document& target_document, size_t desi
return SUCCESS;
}
simdjson_really_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
if(max_capacity < MINIMAL_DOCUMENT_CAPACITY) {
simdjson_inline void parser::set_max_capacity(size_t max_capacity) noexcept {
if(max_capacity > MINIMAL_DOCUMENT_CAPACITY) {
_max_capacity = max_capacity;
} else {
_max_capacity = MINIMAL_DOCUMENT_CAPACITY;
+30 -23
View File
@@ -68,20 +68,20 @@ public:
* to allocate an initial capacity, call allocate() after constructing the parser.
* Defaults to SIMDJSON_MAXSIZE_BYTES (the largest single document simdjson can process).
*/
simdjson_really_inline explicit parser(size_t max_capacity = SIMDJSON_MAXSIZE_BYTES) noexcept;
simdjson_inline explicit parser(size_t max_capacity = SIMDJSON_MAXSIZE_BYTES) noexcept;
/**
* Take another parser's buffers and state.
*
* @param other The parser to take. Its capacity is zeroed.
*/
simdjson_really_inline parser(parser &&other) noexcept;
simdjson_inline parser(parser &&other) noexcept;
parser(const parser &) = delete; ///< @private Disallow copying
/**
* Take another parser's buffers and state.
*
* @param other The parser to take. Its capacity is zeroed.
*/
simdjson_really_inline parser &operator=(parser &&other) noexcept;
simdjson_inline parser &operator=(parser &&other) noexcept;
parser &operator=(const parser &) = delete; ///< @private Disallow copying
/** Deallocate the JSON parser. */
@@ -145,7 +145,9 @@ public:
* ### REQUIRED: Buffer Padding
*
* 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,
* and it is copied into an enlarged temporary buffer before parsing. Thus the following is safe:
@@ -191,17 +193,20 @@ public:
inline simdjson_result<element> parse(const uint8_t *buf, size_t len, bool realloc_if_needed = true) & noexcept;
inline simdjson_result<element> parse(const uint8_t *buf, size_t len, bool realloc_if_needed = true) && =delete;
/** @overload parse(const uint8_t *buf, size_t len, bool realloc_if_needed) */
simdjson_really_inline simdjson_result<element> parse(const char *buf, size_t len, bool realloc_if_needed = true) & noexcept;
simdjson_really_inline simdjson_result<element> parse(const char *buf, size_t len, bool realloc_if_needed = true) && =delete;
simdjson_inline simdjson_result<element> parse(const char *buf, size_t len, bool realloc_if_needed = true) & noexcept;
simdjson_inline simdjson_result<element> parse(const char *buf, size_t len, bool realloc_if_needed = true) && =delete;
/** @overload parse(const uint8_t *buf, size_t len, bool realloc_if_needed) */
simdjson_really_inline simdjson_result<element> parse(const std::string &s) & noexcept;
simdjson_really_inline simdjson_result<element> parse(const std::string &s) && =delete;
simdjson_inline simdjson_result<element> parse(const std::string &s) & noexcept;
simdjson_inline simdjson_result<element> parse(const std::string &s) && =delete;
/** @overload parse(const uint8_t *buf, size_t len, bool realloc_if_needed) */
simdjson_really_inline simdjson_result<element> parse(const padded_string &s) & noexcept;
simdjson_really_inline simdjson_result<element> parse(const padded_string &s) && =delete;
simdjson_inline simdjson_result<element> parse(const padded_string &s) & noexcept;
simdjson_inline simdjson_result<element> parse(const padded_string &s) && =delete;
/** @overload parse(const uint8_t *buf, size_t len, bool realloc_if_needed) */
simdjson_inline simdjson_result<element> parse(const padded_string_view &v) & noexcept;
simdjson_inline simdjson_result<element> parse(const padded_string_view &v) && =delete;
/** @private We do not want to allow implicit conversion from C string to std::string. */
simdjson_really_inline simdjson_result<element> parse(const char *buf) noexcept = delete;
simdjson_inline simdjson_result<element> parse(const char *buf) noexcept = delete;
/**
* Parse a JSON document into a provide document instance and return a temporary reference to it.
@@ -250,17 +255,17 @@ public:
inline simdjson_result<element> parse_into_document(document& doc, const uint8_t *buf, size_t len, bool realloc_if_needed = true) & noexcept;
inline simdjson_result<element> parse_into_document(document& doc, const uint8_t *buf, size_t len, bool realloc_if_needed = true) && =delete;
/** @overload parse_into_document(const uint8_t *buf, size_t len, bool realloc_if_needed) */
simdjson_really_inline simdjson_result<element> parse_into_document(document& doc, const char *buf, size_t len, bool realloc_if_needed = true) & noexcept;
simdjson_really_inline simdjson_result<element> parse_into_document(document& doc, const char *buf, size_t len, bool realloc_if_needed = true) && =delete;
simdjson_inline simdjson_result<element> parse_into_document(document& doc, const char *buf, size_t len, bool realloc_if_needed = true) & noexcept;
simdjson_inline simdjson_result<element> parse_into_document(document& doc, const char *buf, size_t len, bool realloc_if_needed = true) && =delete;
/** @overload parse_into_document(const uint8_t *buf, size_t len, bool realloc_if_needed) */
simdjson_really_inline simdjson_result<element> parse_into_document(document& doc, const std::string &s) & noexcept;
simdjson_really_inline simdjson_result<element> parse_into_document(document& doc, const std::string &s) && =delete;
simdjson_inline simdjson_result<element> parse_into_document(document& doc, const std::string &s) & noexcept;
simdjson_inline simdjson_result<element> parse_into_document(document& doc, const std::string &s) && =delete;
/** @overload parse_into_document(const uint8_t *buf, size_t len, bool realloc_if_needed) */
simdjson_really_inline simdjson_result<element> parse_into_document(document& doc, const padded_string &s) & noexcept;
simdjson_really_inline simdjson_result<element> parse_into_document(document& doc, const padded_string &s) && =delete;
simdjson_inline simdjson_result<element> parse_into_document(document& doc, const padded_string &s) & noexcept;
simdjson_inline simdjson_result<element> parse_into_document(document& doc, const padded_string &s) && =delete;
/** @private We do not want to allow implicit conversion from C string to std::string. */
simdjson_really_inline simdjson_result<element> parse_into_document(document& doc, const char *buf) noexcept = delete;
simdjson_inline simdjson_result<element> parse_into_document(document& doc, const char *buf) noexcept = delete;
/**
* Load a file containing many JSON documents.
@@ -405,7 +410,9 @@ public:
* ### REQUIRED: Buffer Padding
*
* 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
*
@@ -472,7 +479,7 @@ public:
*
* @return Current capacity, in bytes.
*/
simdjson_really_inline size_t capacity() const noexcept;
simdjson_inline size_t capacity() const noexcept;
/**
* The largest document this parser can automatically support.
@@ -481,14 +488,14 @@ public:
*
* @return Maximum capacity, in bytes.
*/
simdjson_really_inline size_t max_capacity() const noexcept;
simdjson_inline size_t max_capacity() const noexcept;
/**
* The maximum level of nested object and arrays supported by this parser.
*
* @return Maximum depth, in bytes.
*/
simdjson_really_inline size_t max_depth() const noexcept;
simdjson_inline size_t max_depth() const noexcept;
/**
* Set max_capacity. This is the largest document this parser can automatically support.
@@ -504,7 +511,7 @@ public:
*
* @param max_capacity The new maximum capacity, in bytes.
*/
simdjson_really_inline void set_max_capacity(size_t max_capacity) noexcept;
simdjson_inline void set_max_capacity(size_t max_capacity) noexcept;
#ifdef SIMDJSON_THREADS_ENABLED
/**
+19 -19
View File
@@ -107,19 +107,19 @@ namespace internal {
* Minifier/formatter code.
**/
simdjson_really_inline void mini_formatter::number(uint64_t x) {
simdjson_inline void mini_formatter::number(uint64_t x) {
char number_buffer[24];
char *newp = fast_itoa(number_buffer, x);
buffer.insert(buffer.end(), number_buffer, newp);
}
simdjson_really_inline void mini_formatter::number(int64_t x) {
simdjson_inline void mini_formatter::number(int64_t x) {
char number_buffer[24];
char *newp = fast_itoa(number_buffer, x);
buffer.insert(buffer.end(), number_buffer, newp);
}
simdjson_really_inline void mini_formatter::number(double x) {
simdjson_inline void mini_formatter::number(double x) {
char number_buffer[24];
// Currently, passing the nullptr to the second argument is
// safe because our implementation does not check the second
@@ -128,31 +128,31 @@ simdjson_really_inline void mini_formatter::number(double x) {
buffer.insert(buffer.end(), number_buffer, newp);
}
simdjson_really_inline void mini_formatter::start_array() { one_char('['); }
simdjson_really_inline void mini_formatter::end_array() { one_char(']'); }
simdjson_really_inline void mini_formatter::start_object() { one_char('{'); }
simdjson_really_inline void mini_formatter::end_object() { one_char('}'); }
simdjson_really_inline void mini_formatter::comma() { one_char(','); }
simdjson_inline void mini_formatter::start_array() { one_char('['); }
simdjson_inline void mini_formatter::end_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_really_inline void mini_formatter::true_atom() {
simdjson_inline void mini_formatter::true_atom() {
const char * s = "true";
buffer.insert(buffer.end(), s, s + 4);
}
simdjson_really_inline void mini_formatter::false_atom() {
simdjson_inline void mini_formatter::false_atom() {
const char * s = "false";
buffer.insert(buffer.end(), s, s + 5);
}
simdjson_really_inline void mini_formatter::null_atom() {
simdjson_inline void mini_formatter::null_atom() {
const char * s = "null";
buffer.insert(buffer.end(), s, s + 4);
}
simdjson_really_inline void mini_formatter::one_char(char c) { buffer.push_back(c); }
simdjson_really_inline void mini_formatter::key(std::string_view unescaped) {
simdjson_inline void mini_formatter::one_char(char c) { buffer.push_back(c); }
simdjson_inline void mini_formatter::key(std::string_view unescaped) {
string(unescaped);
one_char(':');
}
simdjson_really_inline void mini_formatter::string(std::string_view unescaped) {
simdjson_inline void mini_formatter::string(std::string_view unescaped) {
one_char('\"');
size_t i = 0;
// Fast path for the case where we have no control character, no ", and no backslash.
@@ -235,7 +235,7 @@ inline void mini_formatter::clear() {
buffer.clear();
}
simdjson_really_inline std::string_view mini_formatter::str() const {
simdjson_inline std::string_view mini_formatter::str() const {
return std::string_view(buffer.data(), buffer.size());
}
@@ -406,18 +406,18 @@ inline void string_builder<serializer>::append(simdjson::dom::array value) {
}
template <class serializer>
simdjson_really_inline void string_builder<serializer>::append(simdjson::dom::key_value_pair kv) {
simdjson_inline void string_builder<serializer>::append(simdjson::dom::key_value_pair kv) {
format.key(kv.key);
append(kv.value);
}
template <class serializer>
simdjson_really_inline void string_builder<serializer>::clear() {
simdjson_inline void string_builder<serializer>::clear() {
format.clear();
}
template <class serializer>
simdjson_really_inline std::string_view string_builder<serializer>::str() const {
simdjson_inline std::string_view string_builder<serializer>::str() const {
return format.str();
}
@@ -425,4 +425,4 @@ simdjson_really_inline std::string_view string_builder<serializer>::str() const
} // namespace internal
} // namespace simdjson
#endif
#endif
+20 -20
View File
@@ -40,7 +40,7 @@ public:
/** Append an object to the builder (to be printed) **/
inline void append(simdjson::dom::object value);
/** Reset the builder (so that it would print the empty string) **/
simdjson_really_inline void clear();
simdjson_inline void clear();
/**
* Get access to the string. The string_view is owned by the builder
* and it is invalid to use it after the string_builder has been
@@ -48,9 +48,9 @@ public:
* However you can make a copy of the string_view on memory that you
* own.
*/
simdjson_really_inline std::string_view str() const;
simdjson_inline std::string_view str() const;
/** Append a key_value_pair to the builder (to be printed) **/
simdjson_really_inline void append(simdjson::dom::key_value_pair value);
simdjson_inline void append(simdjson::dom::key_value_pair value);
private:
formatter format{};
};
@@ -64,43 +64,43 @@ class mini_formatter {
public:
mini_formatter() = default;
/** Add a comma **/
simdjson_really_inline void comma();
simdjson_inline void comma();
/** Start an array, prints [ **/
simdjson_really_inline void start_array();
simdjson_inline void start_array();
/** End an array, prints ] **/
simdjson_really_inline void end_array();
simdjson_inline void end_array();
/** Start an array, prints { **/
simdjson_really_inline void start_object();
simdjson_inline void start_object();
/** Start an array, prints } **/
simdjson_really_inline void end_object();
simdjson_inline void end_object();
/** Prints a true **/
simdjson_really_inline void true_atom();
simdjson_inline void true_atom();
/** Prints a false **/
simdjson_really_inline void false_atom();
simdjson_inline void false_atom();
/** Prints a null **/
simdjson_really_inline void null_atom();
simdjson_inline void null_atom();
/** Prints a number **/
simdjson_really_inline void number(int64_t x);
simdjson_inline void number(int64_t x);
/** Prints a number **/
simdjson_really_inline void number(uint64_t x);
simdjson_inline void number(uint64_t x);
/** Prints a number **/
simdjson_really_inline void number(double x);
simdjson_inline void number(double x);
/** Prints a key (string + colon) **/
simdjson_really_inline void key(std::string_view unescaped);
simdjson_inline void key(std::string_view unescaped);
/** Prints a string. The string is escaped as needed. **/
simdjson_really_inline void string(std::string_view unescaped);
simdjson_inline void string(std::string_view unescaped);
/** Clears out the content. **/
simdjson_really_inline void clear();
simdjson_inline void clear();
/**
* Get access to the buffer, it is owned by the instance, but
* the user can make a copy.
**/
simdjson_really_inline std::string_view str() const;
simdjson_inline std::string_view str() const;
private:
// implementation details (subject to change)
/** Prints one character **/
simdjson_really_inline void one_char(char c);
simdjson_inline void one_char(char c);
/** Backing buffer **/
std::vector<char> buffer{}; // not ideal!
};
@@ -216,4 +216,4 @@ std::string minify(simdjson_result<T> x) {
} // namespace simdjson
#endif
#endif

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