simdjson 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (132) hide show
  1. checksums.yaml +7 -0
  2. data/.clang-format +5 -0
  3. data/.gitignore +14 -0
  4. data/.gitmodules +3 -0
  5. data/.rubocop.yml +9 -0
  6. data/.travis.yml +7 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +39 -0
  10. data/Rakefile +32 -0
  11. data/benchmark/apache_builds.json +4421 -0
  12. data/benchmark/demo.json +15 -0
  13. data/benchmark/github_events.json +1390 -0
  14. data/benchmark/run_benchmark.rb +30 -0
  15. data/ext/simdjson/extconf.rb +22 -0
  16. data/ext/simdjson/simdjson.cpp +76 -0
  17. data/ext/simdjson/simdjson.hpp +6 -0
  18. data/lib/simdjson/version.rb +3 -0
  19. data/lib/simdjson.rb +2 -0
  20. data/simdjson.gemspec +35 -0
  21. data/vendor/.gitkeep +0 -0
  22. data/vendor/simdjson/AUTHORS +3 -0
  23. data/vendor/simdjson/CMakeLists.txt +63 -0
  24. data/vendor/simdjson/CONTRIBUTORS +27 -0
  25. data/vendor/simdjson/Dockerfile +10 -0
  26. data/vendor/simdjson/LICENSE +201 -0
  27. data/vendor/simdjson/Makefile +203 -0
  28. data/vendor/simdjson/Notes.md +85 -0
  29. data/vendor/simdjson/README.md +581 -0
  30. data/vendor/simdjson/amalgamation.sh +158 -0
  31. data/vendor/simdjson/benchmark/CMakeLists.txt +8 -0
  32. data/vendor/simdjson/benchmark/benchmark.h +223 -0
  33. data/vendor/simdjson/benchmark/distinctuseridcompetition.cpp +347 -0
  34. data/vendor/simdjson/benchmark/linux/linux-perf-events.h +93 -0
  35. data/vendor/simdjson/benchmark/minifiercompetition.cpp +181 -0
  36. data/vendor/simdjson/benchmark/parse.cpp +393 -0
  37. data/vendor/simdjson/benchmark/parseandstatcompetition.cpp +305 -0
  38. data/vendor/simdjson/benchmark/parsingcompetition.cpp +298 -0
  39. data/vendor/simdjson/benchmark/statisticalmodel.cpp +208 -0
  40. data/vendor/simdjson/dependencies/jsoncppdist/json/json-forwards.h +344 -0
  41. data/vendor/simdjson/dependencies/jsoncppdist/json/json.h +2366 -0
  42. data/vendor/simdjson/dependencies/jsoncppdist/jsoncpp.cpp +5418 -0
  43. data/vendor/simdjson/doc/apache_builds.jsonparseandstat.png +0 -0
  44. data/vendor/simdjson/doc/gbps.png +0 -0
  45. data/vendor/simdjson/doc/github_events.jsonparseandstat.png +0 -0
  46. data/vendor/simdjson/doc/twitter.jsonparseandstat.png +0 -0
  47. data/vendor/simdjson/doc/update-center.jsonparseandstat.png +0 -0
  48. data/vendor/simdjson/images/halvarflake.png +0 -0
  49. data/vendor/simdjson/images/logo.png +0 -0
  50. data/vendor/simdjson/include/simdjson/common_defs.h +102 -0
  51. data/vendor/simdjson/include/simdjson/isadetection.h +152 -0
  52. data/vendor/simdjson/include/simdjson/jsoncharutils.h +301 -0
  53. data/vendor/simdjson/include/simdjson/jsonformatutils.h +202 -0
  54. data/vendor/simdjson/include/simdjson/jsonioutil.h +32 -0
  55. data/vendor/simdjson/include/simdjson/jsonminifier.h +30 -0
  56. data/vendor/simdjson/include/simdjson/jsonparser.h +250 -0
  57. data/vendor/simdjson/include/simdjson/numberparsing.h +587 -0
  58. data/vendor/simdjson/include/simdjson/padded_string.h +70 -0
  59. data/vendor/simdjson/include/simdjson/parsedjson.h +544 -0
  60. data/vendor/simdjson/include/simdjson/portability.h +172 -0
  61. data/vendor/simdjson/include/simdjson/simdjson.h +44 -0
  62. data/vendor/simdjson/include/simdjson/simdjson_version.h +13 -0
  63. data/vendor/simdjson/include/simdjson/simdprune_tables.h +35074 -0
  64. data/vendor/simdjson/include/simdjson/simdutf8check_arm64.h +180 -0
  65. data/vendor/simdjson/include/simdjson/simdutf8check_haswell.h +198 -0
  66. data/vendor/simdjson/include/simdjson/simdutf8check_westmere.h +169 -0
  67. data/vendor/simdjson/include/simdjson/stage1_find_marks.h +121 -0
  68. data/vendor/simdjson/include/simdjson/stage1_find_marks_arm64.h +210 -0
  69. data/vendor/simdjson/include/simdjson/stage1_find_marks_flatten.h +93 -0
  70. data/vendor/simdjson/include/simdjson/stage1_find_marks_flatten_haswell.h +95 -0
  71. data/vendor/simdjson/include/simdjson/stage1_find_marks_haswell.h +210 -0
  72. data/vendor/simdjson/include/simdjson/stage1_find_marks_macros.h +239 -0
  73. data/vendor/simdjson/include/simdjson/stage1_find_marks_westmere.h +194 -0
  74. data/vendor/simdjson/include/simdjson/stage2_build_tape.h +85 -0
  75. data/vendor/simdjson/include/simdjson/stringparsing.h +105 -0
  76. data/vendor/simdjson/include/simdjson/stringparsing_arm64.h +56 -0
  77. data/vendor/simdjson/include/simdjson/stringparsing_haswell.h +43 -0
  78. data/vendor/simdjson/include/simdjson/stringparsing_macros.h +88 -0
  79. data/vendor/simdjson/include/simdjson/stringparsing_westmere.h +41 -0
  80. data/vendor/simdjson/jsonexamples/small/jsoniter_scala/README.md +4 -0
  81. data/vendor/simdjson/scripts/dumpsimplestats.sh +11 -0
  82. data/vendor/simdjson/scripts/issue150.sh +14 -0
  83. data/vendor/simdjson/scripts/javascript/README.md +3 -0
  84. data/vendor/simdjson/scripts/javascript/generatelargejson.js +19 -0
  85. data/vendor/simdjson/scripts/minifier.sh +11 -0
  86. data/vendor/simdjson/scripts/parseandstat.sh +24 -0
  87. data/vendor/simdjson/scripts/parser.sh +11 -0
  88. data/vendor/simdjson/scripts/parsingcompdata.sh +26 -0
  89. data/vendor/simdjson/scripts/plotparse.sh +98 -0
  90. data/vendor/simdjson/scripts/selectparser.sh +11 -0
  91. data/vendor/simdjson/scripts/setupfortesting/disablehyperthreading.sh +15 -0
  92. data/vendor/simdjson/scripts/setupfortesting/powerpolicy.sh +32 -0
  93. data/vendor/simdjson/scripts/setupfortesting/setupfortesting.sh +6 -0
  94. data/vendor/simdjson/scripts/setupfortesting/turboboost.sh +51 -0
  95. data/vendor/simdjson/scripts/testjson2json.sh +99 -0
  96. data/vendor/simdjson/scripts/transitions/Makefile +10 -0
  97. data/vendor/simdjson/scripts/transitions/generatetransitions.cpp +20 -0
  98. data/vendor/simdjson/singleheader/README.md +1 -0
  99. data/vendor/simdjson/singleheader/amalgamation_demo.cpp +20 -0
  100. data/vendor/simdjson/singleheader/simdjson.cpp +1652 -0
  101. data/vendor/simdjson/singleheader/simdjson.h +39692 -0
  102. data/vendor/simdjson/src/CMakeLists.txt +67 -0
  103. data/vendor/simdjson/src/jsonioutil.cpp +35 -0
  104. data/vendor/simdjson/src/jsonminifier.cpp +285 -0
  105. data/vendor/simdjson/src/jsonparser.cpp +91 -0
  106. data/vendor/simdjson/src/parsedjson.cpp +323 -0
  107. data/vendor/simdjson/src/parsedjsoniterator.cpp +272 -0
  108. data/vendor/simdjson/src/simdjson.cpp +30 -0
  109. data/vendor/simdjson/src/stage1_find_marks.cpp +41 -0
  110. data/vendor/simdjson/src/stage2_build_tape.cpp +567 -0
  111. data/vendor/simdjson/style/clang-format-check.sh +25 -0
  112. data/vendor/simdjson/style/clang-format.sh +25 -0
  113. data/vendor/simdjson/style/run-clang-format.py +326 -0
  114. data/vendor/simdjson/tape.md +134 -0
  115. data/vendor/simdjson/tests/CMakeLists.txt +25 -0
  116. data/vendor/simdjson/tests/allparserscheckfile.cpp +192 -0
  117. data/vendor/simdjson/tests/basictests.cpp +75 -0
  118. data/vendor/simdjson/tests/jsoncheck.cpp +136 -0
  119. data/vendor/simdjson/tests/numberparsingcheck.cpp +224 -0
  120. data/vendor/simdjson/tests/pointercheck.cpp +38 -0
  121. data/vendor/simdjson/tests/singleheadertest.cpp +22 -0
  122. data/vendor/simdjson/tests/stringparsingcheck.cpp +408 -0
  123. data/vendor/simdjson/tools/CMakeLists.txt +3 -0
  124. data/vendor/simdjson/tools/cmake/FindCTargets.cmake +15 -0
  125. data/vendor/simdjson/tools/cmake/FindOptions.cmake +52 -0
  126. data/vendor/simdjson/tools/json2json.cpp +112 -0
  127. data/vendor/simdjson/tools/jsonpointer.cpp +93 -0
  128. data/vendor/simdjson/tools/jsonstats.cpp +143 -0
  129. data/vendor/simdjson/tools/minify.cpp +21 -0
  130. data/vendor/simdjson/tools/release.py +125 -0
  131. data/vendor/simdjson/windows/dirent_portable.h +1043 -0
  132. metadata +273 -0
@@ -0,0 +1,67 @@
1
+ if(${CMAKE_C_COMPILER_ID} MATCHES "Intel") # icc / icpc
2
+ # prevent shared libraries from depending on Intel provided libraries
3
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-intel")
4
+ endif()
5
+
6
+ include(GNUInstallDirs)
7
+
8
+ # we default on a shared library.
9
+ if(SIMDJSON_BUILD_STATIC)
10
+ set(SIMDJSON_LIB_TYPE STATIC)
11
+ MESSAGE( STATUS "Building a static library." )
12
+ else()
13
+ MESSAGE( STATUS "Building a dynamic library (default)." )
14
+ set(SIMDJSON_LIB_TYPE SHARED)
15
+ endif()
16
+
17
+ MESSAGE( STATUS "SIMDJSON_LIB_TYPE: " ${SIMDJSON_LIB_TYPE})
18
+ set(SIMDJSON_SRC
19
+ jsonioutil.cpp
20
+ jsonminifier.cpp
21
+ jsonparser.cpp
22
+ stage1_find_marks.cpp
23
+ stage2_build_tape.cpp
24
+ parsedjson.cpp
25
+ parsedjsoniterator.cpp
26
+ simdjson.cpp
27
+ )
28
+
29
+ add_library(${SIMDJSON_LIB_NAME} ${SIMDJSON_LIB_TYPE} ${SIMDJSON_SRC})
30
+
31
+ target_include_directories(${SIMDJSON_LIB_NAME}
32
+ PUBLIC
33
+ $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
34
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
35
+ )
36
+
37
+ install(TARGETS ${SIMDJSON_LIB_NAME}
38
+ EXPORT ${SIMDJSON_LIB_NAME}-config
39
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
40
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
41
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
42
+ )
43
+
44
+ install(EXPORT ${SIMDJSON_LIB_NAME}-config
45
+ FILE ${SIMDJSON_LIB_NAME}-config.cmake
46
+ NAMESPACE ${SIMDJSON_LIB_NAME}::
47
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${SIMDJSON_LIB_NAME}
48
+ )
49
+
50
+ if(NOT MSVC)
51
+ ## We output the library at the root of the current directory where cmake is invoked
52
+ ## This is handy but Visual Studio will happily ignore us
53
+ set_target_properties(${SIMDJSON_LIB_NAME} PROPERTIES
54
+ LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}
55
+ VERSION ${SIMDJSON_LIB_VERSION}
56
+ SOVERSION ${SIMDJSON_LIB_SOVERSION})
57
+ MESSAGE( STATUS "Library output directory (does not apply to Visual Studio): " ${CMAKE_BINARY_DIR})
58
+ endif()
59
+
60
+ if(MSVC AND (SIMDJSON_LIB_TYPE STREQUAL "SHARED"))
61
+ if (CMAKE_VERSION VERSION_LESS 3.4)
62
+ MESSAGE( STATUS "To build a Windows DLL using Visual Studio, you may need cmake 3.4 or better." )
63
+ endif()
64
+ MESSAGE( STATUS "Building a Windows DLL using Visual Studio, exporting all symbols automatically." )
65
+ set_target_properties(${SIMDJSON_LIB_NAME}
66
+ PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS 1)
67
+ endif()
@@ -0,0 +1,35 @@
1
+ #include "simdjson/jsonioutil.h"
2
+ #include <cstdlib>
3
+ #include <cstring>
4
+
5
+ namespace simdjson {
6
+ char *allocate_padded_buffer(size_t length) {
7
+ // we could do a simple malloc
8
+ // return (char *) malloc(length + SIMDJSON_PADDING);
9
+ // However, we might as well align to cache lines...
10
+ size_t totalpaddedlength = length + SIMDJSON_PADDING;
11
+ char *padded_buffer = aligned_malloc_char(64, totalpaddedlength);
12
+ return padded_buffer;
13
+ }
14
+
15
+ padded_string get_corpus(const std::string &filename) {
16
+ std::FILE *fp = std::fopen(filename.c_str(), "rb");
17
+ if (fp != nullptr) {
18
+ std::fseek(fp, 0, SEEK_END);
19
+ size_t len = std::ftell(fp);
20
+ padded_string s(len);
21
+ if (s.data() == nullptr) {
22
+ std::fclose(fp);
23
+ throw std::runtime_error("could not allocate memory");
24
+ }
25
+ std::rewind(fp);
26
+ size_t readb = std::fread(s.data(), 1, len, fp);
27
+ std::fclose(fp);
28
+ if (readb != len) {
29
+ throw std::runtime_error("could not read the data");
30
+ }
31
+ return s;
32
+ }
33
+ throw std::runtime_error("could not load corpus");
34
+ }
35
+ } // namespace simdjson
@@ -0,0 +1,285 @@
1
+ #include "simdjson/portability.h"
2
+ #include <cstdint>
3
+
4
+ #ifndef __AVX2__
5
+
6
+ namespace simdjson {
7
+ static uint8_t jump_table[256 * 3] = {
8
+ 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0,
9
+ 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1,
10
+ 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,
11
+ 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0,
12
+ 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1,
13
+ 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,
14
+ 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0,
15
+ 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1,
16
+ 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,
17
+ 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0,
18
+ 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1,
19
+ 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,
20
+ 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0,
21
+ 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1,
22
+ 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,
23
+ 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0,
24
+ 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1,
25
+ 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,
26
+ 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0,
27
+ 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1,
28
+ 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,
29
+ 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0,
30
+ 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1,
31
+ 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,
32
+ 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0,
33
+ 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1,
34
+ 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,
35
+ 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0,
36
+ 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1,
37
+ 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,
38
+ 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,
39
+ };
40
+
41
+ size_t json_minify(const unsigned char *bytes, size_t how_many,
42
+ unsigned char *out) {
43
+ size_t i = 0, pos = 0;
44
+ uint8_t quote = 0;
45
+ uint8_t nonescape = 1;
46
+
47
+ while (i < how_many) {
48
+ unsigned char c = bytes[i];
49
+ uint8_t *meta = jump_table + 3 * c;
50
+
51
+ quote = quote ^ (meta[0] & nonescape);
52
+ out[pos] = c;
53
+ pos += meta[2] | quote;
54
+
55
+ i += 1;
56
+ nonescape = (~nonescape) | (meta[1]);
57
+ }
58
+ return pos;
59
+ }
60
+ } // namespace simdjson
61
+ #else
62
+ #include "simdjson/simdprune_tables.h"
63
+ #include <cstring>
64
+
65
+ namespace simdjson {
66
+
67
+ // some intrinsics are missing under GCC?
68
+ #ifndef __clang__
69
+ #ifndef _MSC_VER
70
+ static __m256i inline _mm256_loadu2_m128i(__m128i const *__addr_hi,
71
+ __m128i const *__addr_lo) {
72
+ __m256i __v256 = _mm256_castsi128_si256(_mm_loadu_si128(__addr_lo));
73
+ return _mm256_insertf128_si256(__v256, _mm_loadu_si128(__addr_hi), 1);
74
+ }
75
+
76
+ static inline void _mm256_storeu2_m128i(__m128i *__addr_hi, __m128i *__addr_lo,
77
+ __m256i __a) {
78
+ __m128i __v128;
79
+ __v128 = _mm256_castsi256_si128(__a);
80
+ _mm_storeu_si128(__addr_lo, __v128);
81
+ __v128 = _mm256_extractf128_si256(__a, 1);
82
+ _mm_storeu_si128(__addr_hi, __v128);
83
+ }
84
+ #endif
85
+ #endif
86
+
87
+ // a straightforward comparison of a mask against input.
88
+ static uint64_t cmp_mask_against_input_mini(__m256i input_lo, __m256i input_hi,
89
+ __m256i mask) {
90
+ __m256i cmp_res_0 = _mm256_cmpeq_epi8(input_lo, mask);
91
+ uint64_t res_0 = static_cast<uint32_t>(_mm256_movemask_epi8(cmp_res_0));
92
+ __m256i cmp_res_1 = _mm256_cmpeq_epi8(input_hi, mask);
93
+ uint64_t res_1 = _mm256_movemask_epi8(cmp_res_1);
94
+ return res_0 | (res_1 << 32);
95
+ }
96
+
97
+ // take input from buf and remove useless whitespace, input and output can be
98
+ // the same, result is null terminated, return the string length (minus the null
99
+ // termination)
100
+ size_t json_minify(const uint8_t *buf, size_t len, uint8_t *out) {
101
+ // Useful constant masks
102
+ const uint64_t even_bits = 0x5555555555555555ULL;
103
+ const uint64_t odd_bits = ~even_bits;
104
+ uint8_t *initout(out);
105
+ uint64_t prev_iter_ends_odd_backslash =
106
+ 0ULL; // either 0 or 1, but a 64-bit value
107
+ uint64_t prev_iter_inside_quote = 0ULL; // either all zeros or all ones
108
+ size_t idx = 0;
109
+ if (len >= 64) {
110
+ size_t avx_len = len - 63;
111
+
112
+ for (; idx < avx_len; idx += 64) {
113
+ __m256i input_lo =
114
+ _mm256_loadu_si256(reinterpret_cast<const __m256i *>(buf + idx + 0));
115
+ __m256i input_hi =
116
+ _mm256_loadu_si256(reinterpret_cast<const __m256i *>(buf + idx + 32));
117
+ uint64_t bs_bits = cmp_mask_against_input_mini(input_lo, input_hi,
118
+ _mm256_set1_epi8('\\'));
119
+ uint64_t start_edges = bs_bits & ~(bs_bits << 1);
120
+ uint64_t even_start_mask = even_bits ^ prev_iter_ends_odd_backslash;
121
+ uint64_t even_starts = start_edges & even_start_mask;
122
+ uint64_t odd_starts = start_edges & ~even_start_mask;
123
+ uint64_t even_carries = bs_bits + even_starts;
124
+ uint64_t odd_carries;
125
+ bool iter_ends_odd_backslash =
126
+ add_overflow(bs_bits, odd_starts, &odd_carries);
127
+ odd_carries |= prev_iter_ends_odd_backslash;
128
+ prev_iter_ends_odd_backslash = iter_ends_odd_backslash ? 0x1ULL : 0x0ULL;
129
+ uint64_t even_carry_ends = even_carries & ~bs_bits;
130
+ uint64_t odd_carry_ends = odd_carries & ~bs_bits;
131
+ uint64_t even_start_odd_end = even_carry_ends & odd_bits;
132
+ uint64_t odd_start_even_end = odd_carry_ends & even_bits;
133
+ uint64_t odd_ends = even_start_odd_end | odd_start_even_end;
134
+ uint64_t quote_bits = cmp_mask_against_input_mini(input_lo, input_hi,
135
+ _mm256_set1_epi8('"'));
136
+ quote_bits = quote_bits & ~odd_ends;
137
+ uint64_t quote_mask = _mm_cvtsi128_si64(_mm_clmulepi64_si128(
138
+ _mm_set_epi64x(0ULL, quote_bits), _mm_set1_epi8(0xFF), 0));
139
+ quote_mask ^= prev_iter_inside_quote;
140
+ prev_iter_inside_quote = static_cast<uint64_t>(
141
+ static_cast<int64_t>(quote_mask) >>
142
+ 63); // might be undefined behavior, should be fully defined in C++20,
143
+ // ok according to John Regher from Utah University
144
+ const __m256i low_nibble_mask = _mm256_setr_epi8(
145
+ // 0 9 a b c d
146
+ 16, 0, 0, 0, 0, 0, 0, 0, 0, 8, 12, 1, 2, 9, 0, 0, 16, 0, 0, 0, 0, 0,
147
+ 0, 0, 0, 8, 12, 1, 2, 9, 0, 0);
148
+ const __m256i high_nibble_mask = _mm256_setr_epi8(
149
+ // 0 2 3 5 7
150
+ 8, 0, 18, 4, 0, 1, 0, 1, 0, 0, 0, 3, 2, 1, 0, 0, 8, 0, 18, 4, 0, 1, 0,
151
+ 1, 0, 0, 0, 3, 2, 1, 0, 0);
152
+ __m256i whitespace_shufti_mask = _mm256_set1_epi8(0x18);
153
+ __m256i v_lo = _mm256_and_si256(
154
+ _mm256_shuffle_epi8(low_nibble_mask, input_lo),
155
+ _mm256_shuffle_epi8(high_nibble_mask,
156
+ _mm256_and_si256(_mm256_srli_epi32(input_lo, 4),
157
+ _mm256_set1_epi8(0x7f))));
158
+
159
+ __m256i v_hi = _mm256_and_si256(
160
+ _mm256_shuffle_epi8(low_nibble_mask, input_hi),
161
+ _mm256_shuffle_epi8(high_nibble_mask,
162
+ _mm256_and_si256(_mm256_srli_epi32(input_hi, 4),
163
+ _mm256_set1_epi8(0x7f))));
164
+ __m256i tmp_ws_lo = _mm256_cmpeq_epi8(
165
+ _mm256_and_si256(v_lo, whitespace_shufti_mask), _mm256_set1_epi8(0));
166
+ __m256i tmp_ws_hi = _mm256_cmpeq_epi8(
167
+ _mm256_and_si256(v_hi, whitespace_shufti_mask), _mm256_set1_epi8(0));
168
+
169
+ uint64_t ws_res_0 =
170
+ static_cast<uint32_t>(_mm256_movemask_epi8(tmp_ws_lo));
171
+ uint64_t ws_res_1 = _mm256_movemask_epi8(tmp_ws_hi);
172
+ uint64_t whitespace = ~(ws_res_0 | (ws_res_1 << 32));
173
+ whitespace &= ~quote_mask;
174
+ int mask1 = whitespace & 0xFFFF;
175
+ int mask2 = (whitespace >> 16) & 0xFFFF;
176
+ int mask3 = (whitespace >> 32) & 0xFFFF;
177
+ int mask4 = (whitespace >> 48) & 0xFFFF;
178
+ int pop1 = hamming((~whitespace) & 0xFFFF);
179
+ int pop2 = hamming((~whitespace) & UINT64_C(0xFFFFFFFF));
180
+ int pop3 = hamming((~whitespace) & UINT64_C(0xFFFFFFFFFFFF));
181
+ int pop4 = hamming((~whitespace));
182
+ __m256i vmask1 = _mm256_loadu2_m128i(
183
+ reinterpret_cast<const __m128i *>(mask128_epi8) + (mask2 & 0x7FFF),
184
+ reinterpret_cast<const __m128i *>(mask128_epi8) + (mask1 & 0x7FFF));
185
+ __m256i vmask2 = _mm256_loadu2_m128i(
186
+ reinterpret_cast<const __m128i *>(mask128_epi8) + (mask4 & 0x7FFF),
187
+ reinterpret_cast<const __m128i *>(mask128_epi8) + (mask3 & 0x7FFF));
188
+ __m256i result1 = _mm256_shuffle_epi8(input_lo, vmask1);
189
+ __m256i result2 = _mm256_shuffle_epi8(input_hi, vmask2);
190
+ _mm256_storeu2_m128i(reinterpret_cast<__m128i *>(out + pop1),
191
+ reinterpret_cast<__m128i *>(out), result1);
192
+ _mm256_storeu2_m128i(reinterpret_cast<__m128i *>(out + pop3),
193
+ reinterpret_cast<__m128i *>(out + pop2), result2);
194
+ out += pop4;
195
+ }
196
+ }
197
+ // we finish off the job... copying and pasting the code is not ideal here,
198
+ // but it gets the job done.
199
+ if (idx < len) {
200
+ uint8_t buffer[64];
201
+ memset(buffer, 0, 64);
202
+ memcpy(buffer, buf + idx, len - idx);
203
+ __m256i input_lo =
204
+ _mm256_loadu_si256(reinterpret_cast<const __m256i *>(buffer));
205
+ __m256i input_hi =
206
+ _mm256_loadu_si256(reinterpret_cast<const __m256i *>(buffer + 32));
207
+ uint64_t bs_bits =
208
+ cmp_mask_against_input_mini(input_lo, input_hi, _mm256_set1_epi8('\\'));
209
+ uint64_t start_edges = bs_bits & ~(bs_bits << 1);
210
+ uint64_t even_start_mask = even_bits ^ prev_iter_ends_odd_backslash;
211
+ uint64_t even_starts = start_edges & even_start_mask;
212
+ uint64_t odd_starts = start_edges & ~even_start_mask;
213
+ uint64_t even_carries = bs_bits + even_starts;
214
+ uint64_t odd_carries;
215
+ // bool iter_ends_odd_backslash =
216
+ add_overflow(bs_bits, odd_starts, &odd_carries);
217
+ odd_carries |= prev_iter_ends_odd_backslash;
218
+ // prev_iter_ends_odd_backslash = iter_ends_odd_backslash ? 0x1ULL : 0x0ULL;
219
+ // // we never use it
220
+ uint64_t even_carry_ends = even_carries & ~bs_bits;
221
+ uint64_t odd_carry_ends = odd_carries & ~bs_bits;
222
+ uint64_t even_start_odd_end = even_carry_ends & odd_bits;
223
+ uint64_t odd_start_even_end = odd_carry_ends & even_bits;
224
+ uint64_t odd_ends = even_start_odd_end | odd_start_even_end;
225
+ uint64_t quote_bits =
226
+ cmp_mask_against_input_mini(input_lo, input_hi, _mm256_set1_epi8('"'));
227
+ quote_bits = quote_bits & ~odd_ends;
228
+ uint64_t quote_mask = _mm_cvtsi128_si64(_mm_clmulepi64_si128(
229
+ _mm_set_epi64x(0ULL, quote_bits), _mm_set1_epi8(0xFF), 0));
230
+ quote_mask ^= prev_iter_inside_quote;
231
+ // prev_iter_inside_quote = (uint64_t)((int64_t)quote_mask >> 63);// we
232
+ // don't need this anymore
233
+
234
+ __m256i mask_20 = _mm256_set1_epi8(0x20); // c==32
235
+ __m256i mask_70 =
236
+ _mm256_set1_epi8(0x70); // adding 0x70 does not check low 4-bits
237
+ // but moves any value >= 16 above 128
238
+
239
+ __m256i lut_cntrl = _mm256_setr_epi8(
240
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
241
+ 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
242
+ 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00);
243
+
244
+ __m256i tmp_ws_lo = _mm256_or_si256(
245
+ _mm256_cmpeq_epi8(mask_20, input_lo),
246
+ _mm256_shuffle_epi8(lut_cntrl, _mm256_adds_epu8(mask_70, input_lo)));
247
+ __m256i tmp_ws_hi = _mm256_or_si256(
248
+ _mm256_cmpeq_epi8(mask_20, input_hi),
249
+ _mm256_shuffle_epi8(lut_cntrl, _mm256_adds_epu8(mask_70, input_hi)));
250
+ uint64_t ws_res_0 = static_cast<uint32_t>(_mm256_movemask_epi8(tmp_ws_lo));
251
+ uint64_t ws_res_1 = _mm256_movemask_epi8(tmp_ws_hi);
252
+ uint64_t whitespace = (ws_res_0 | (ws_res_1 << 32));
253
+ whitespace &= ~quote_mask;
254
+
255
+ if (len - idx < 64) {
256
+ whitespace |= UINT64_C(0xFFFFFFFFFFFFFFFF) << (len - idx);
257
+ }
258
+ int mask1 = whitespace & 0xFFFF;
259
+ int mask2 = (whitespace >> 16) & 0xFFFF;
260
+ int mask3 = (whitespace >> 32) & 0xFFFF;
261
+ int mask4 = (whitespace >> 48) & 0xFFFF;
262
+ int pop1 = hamming((~whitespace) & 0xFFFF);
263
+ int pop2 = hamming((~whitespace) & UINT64_C(0xFFFFFFFF));
264
+ int pop3 = hamming((~whitespace) & UINT64_C(0xFFFFFFFFFFFF));
265
+ int pop4 = hamming((~whitespace));
266
+ __m256i vmask1 = _mm256_loadu2_m128i(
267
+ reinterpret_cast<const __m128i *>(mask128_epi8) + (mask2 & 0x7FFF),
268
+ reinterpret_cast<const __m128i *>(mask128_epi8) + (mask1 & 0x7FFF));
269
+ __m256i vmask2 = _mm256_loadu2_m128i(
270
+ reinterpret_cast<const __m128i *>(mask128_epi8) + (mask4 & 0x7FFF),
271
+ reinterpret_cast<const __m128i *>(mask128_epi8) + (mask3 & 0x7FFF));
272
+ __m256i result1 = _mm256_shuffle_epi8(input_lo, vmask1);
273
+ __m256i result2 = _mm256_shuffle_epi8(input_hi, vmask2);
274
+ _mm256_storeu2_m128i(reinterpret_cast<__m128i *>(buffer + pop1),
275
+ reinterpret_cast<__m128i *>(buffer), result1);
276
+ _mm256_storeu2_m128i(reinterpret_cast<__m128i *>(buffer + pop3),
277
+ reinterpret_cast<__m128i *>(buffer + pop2), result2);
278
+ memcpy(out, buffer, pop4);
279
+ out += pop4;
280
+ }
281
+ *out = '\0'; // NULL termination
282
+ return out - initout;
283
+ }
284
+ } // namespace simdjson
285
+ #endif
@@ -0,0 +1,91 @@
1
+ #include "simdjson/jsonparser.h"
2
+ #include "simdjson/isadetection.h"
3
+ #include "simdjson/portability.h"
4
+ #include "simdjson/simdjson.h"
5
+
6
+ namespace simdjson {
7
+
8
+ // The function that users are expected to call is json_parse.
9
+ // We have more than one such function because we want to support several
10
+ // instruction sets.
11
+
12
+ // function pointer type for json_parse
13
+ using json_parse_functype = int(const uint8_t *buf, size_t len, ParsedJson &pj,
14
+ bool realloc_if_needed);
15
+
16
+ // Pointer that holds the json_parse implementation corresponding to the
17
+ // available SIMD instruction set
18
+ extern json_parse_functype *json_parse_ptr;
19
+
20
+ int json_parse(const uint8_t *buf, size_t len, ParsedJson &pj,
21
+ bool realloc_if_needed) {
22
+ return json_parse_ptr(buf, len, pj, realloc_if_needed);
23
+ }
24
+
25
+ int json_parse(const char *buf, size_t len, ParsedJson &pj,
26
+ bool realloc_if_needed) {
27
+ return json_parse_ptr(reinterpret_cast<const uint8_t *>(buf), len, pj,
28
+ realloc_if_needed);
29
+ }
30
+
31
+ Architecture find_best_supported_implementation() {
32
+ constexpr uint32_t haswell_flags =
33
+ instruction_set::AVX2 | instruction_set::PCLMULQDQ |
34
+ instruction_set::BMI1 | instruction_set::BMI2;
35
+ constexpr uint32_t westmere_flags =
36
+ instruction_set::SSE42 | instruction_set::PCLMULQDQ;
37
+
38
+ uint32_t supports = detect_supported_architectures();
39
+ // Order from best to worst (within architecture)
40
+ if ((haswell_flags & supports) == haswell_flags)
41
+ return Architecture::HASWELL;
42
+ if ((westmere_flags & supports) == westmere_flags)
43
+ return Architecture::WESTMERE;
44
+ if (instruction_set::NEON)
45
+ return Architecture::ARM64;
46
+
47
+ return Architecture::NONE;
48
+ }
49
+
50
+ // Responsible to select the best json_parse implementation
51
+ int json_parse_dispatch(const uint8_t *buf, size_t len, ParsedJson &pj,
52
+ bool realloc_if_needed) {
53
+ Architecture best_implementation = find_best_supported_implementation();
54
+ // Selecting the best implementation
55
+ switch (best_implementation) {
56
+ #ifdef IS_X86_64
57
+ case Architecture::HASWELL:
58
+ json_parse_ptr = &json_parse_implementation<Architecture::HASWELL>;
59
+ break;
60
+ case Architecture::WESTMERE:
61
+ json_parse_ptr = &json_parse_implementation<Architecture::WESTMERE>;
62
+ break;
63
+ #endif
64
+ #ifdef IS_ARM64
65
+ case Architecture::ARM64:
66
+ json_parse_ptr = &json_parse_implementation<Architecture::ARM64>;
67
+ break;
68
+ #endif
69
+ default:
70
+ std::cerr << "The processor is not supported by simdjson." << std::endl;
71
+ return simdjson::UNEXPECTED_ERROR;
72
+ }
73
+
74
+ return json_parse_ptr(buf, len, pj, realloc_if_needed);
75
+ }
76
+
77
+ json_parse_functype *json_parse_ptr = &json_parse_dispatch;
78
+
79
+ WARN_UNUSED
80
+ ParsedJson build_parsed_json(const uint8_t *buf, size_t len,
81
+ bool realloc_if_needed) {
82
+ ParsedJson pj;
83
+ bool ok = pj.allocate_capacity(len);
84
+ if (ok) {
85
+ json_parse(buf, len, pj, realloc_if_needed);
86
+ } else {
87
+ std::cerr << "failure during memory allocation " << std::endl;
88
+ }
89
+ return pj;
90
+ }
91
+ } // namespace simdjson