simdjson 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.clang-format +5 -0
- data/.gitignore +14 -0
- data/.gitmodules +3 -0
- data/.rubocop.yml +9 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +39 -0
- data/Rakefile +32 -0
- data/benchmark/apache_builds.json +4421 -0
- data/benchmark/demo.json +15 -0
- data/benchmark/github_events.json +1390 -0
- data/benchmark/run_benchmark.rb +30 -0
- data/ext/simdjson/extconf.rb +22 -0
- data/ext/simdjson/simdjson.cpp +76 -0
- data/ext/simdjson/simdjson.hpp +6 -0
- data/lib/simdjson/version.rb +3 -0
- data/lib/simdjson.rb +2 -0
- data/simdjson.gemspec +35 -0
- data/vendor/.gitkeep +0 -0
- data/vendor/simdjson/AUTHORS +3 -0
- data/vendor/simdjson/CMakeLists.txt +63 -0
- data/vendor/simdjson/CONTRIBUTORS +27 -0
- data/vendor/simdjson/Dockerfile +10 -0
- data/vendor/simdjson/LICENSE +201 -0
- data/vendor/simdjson/Makefile +203 -0
- data/vendor/simdjson/Notes.md +85 -0
- data/vendor/simdjson/README.md +581 -0
- data/vendor/simdjson/amalgamation.sh +158 -0
- data/vendor/simdjson/benchmark/CMakeLists.txt +8 -0
- data/vendor/simdjson/benchmark/benchmark.h +223 -0
- data/vendor/simdjson/benchmark/distinctuseridcompetition.cpp +347 -0
- data/vendor/simdjson/benchmark/linux/linux-perf-events.h +93 -0
- data/vendor/simdjson/benchmark/minifiercompetition.cpp +181 -0
- data/vendor/simdjson/benchmark/parse.cpp +393 -0
- data/vendor/simdjson/benchmark/parseandstatcompetition.cpp +305 -0
- data/vendor/simdjson/benchmark/parsingcompetition.cpp +298 -0
- data/vendor/simdjson/benchmark/statisticalmodel.cpp +208 -0
- data/vendor/simdjson/dependencies/jsoncppdist/json/json-forwards.h +344 -0
- data/vendor/simdjson/dependencies/jsoncppdist/json/json.h +2366 -0
- data/vendor/simdjson/dependencies/jsoncppdist/jsoncpp.cpp +5418 -0
- data/vendor/simdjson/doc/apache_builds.jsonparseandstat.png +0 -0
- data/vendor/simdjson/doc/gbps.png +0 -0
- data/vendor/simdjson/doc/github_events.jsonparseandstat.png +0 -0
- data/vendor/simdjson/doc/twitter.jsonparseandstat.png +0 -0
- data/vendor/simdjson/doc/update-center.jsonparseandstat.png +0 -0
- data/vendor/simdjson/images/halvarflake.png +0 -0
- data/vendor/simdjson/images/logo.png +0 -0
- data/vendor/simdjson/include/simdjson/common_defs.h +102 -0
- data/vendor/simdjson/include/simdjson/isadetection.h +152 -0
- data/vendor/simdjson/include/simdjson/jsoncharutils.h +301 -0
- data/vendor/simdjson/include/simdjson/jsonformatutils.h +202 -0
- data/vendor/simdjson/include/simdjson/jsonioutil.h +32 -0
- data/vendor/simdjson/include/simdjson/jsonminifier.h +30 -0
- data/vendor/simdjson/include/simdjson/jsonparser.h +250 -0
- data/vendor/simdjson/include/simdjson/numberparsing.h +587 -0
- data/vendor/simdjson/include/simdjson/padded_string.h +70 -0
- data/vendor/simdjson/include/simdjson/parsedjson.h +544 -0
- data/vendor/simdjson/include/simdjson/portability.h +172 -0
- data/vendor/simdjson/include/simdjson/simdjson.h +44 -0
- data/vendor/simdjson/include/simdjson/simdjson_version.h +13 -0
- data/vendor/simdjson/include/simdjson/simdprune_tables.h +35074 -0
- data/vendor/simdjson/include/simdjson/simdutf8check_arm64.h +180 -0
- data/vendor/simdjson/include/simdjson/simdutf8check_haswell.h +198 -0
- data/vendor/simdjson/include/simdjson/simdutf8check_westmere.h +169 -0
- data/vendor/simdjson/include/simdjson/stage1_find_marks.h +121 -0
- data/vendor/simdjson/include/simdjson/stage1_find_marks_arm64.h +210 -0
- data/vendor/simdjson/include/simdjson/stage1_find_marks_flatten.h +93 -0
- data/vendor/simdjson/include/simdjson/stage1_find_marks_flatten_haswell.h +95 -0
- data/vendor/simdjson/include/simdjson/stage1_find_marks_haswell.h +210 -0
- data/vendor/simdjson/include/simdjson/stage1_find_marks_macros.h +239 -0
- data/vendor/simdjson/include/simdjson/stage1_find_marks_westmere.h +194 -0
- data/vendor/simdjson/include/simdjson/stage2_build_tape.h +85 -0
- data/vendor/simdjson/include/simdjson/stringparsing.h +105 -0
- data/vendor/simdjson/include/simdjson/stringparsing_arm64.h +56 -0
- data/vendor/simdjson/include/simdjson/stringparsing_haswell.h +43 -0
- data/vendor/simdjson/include/simdjson/stringparsing_macros.h +88 -0
- data/vendor/simdjson/include/simdjson/stringparsing_westmere.h +41 -0
- data/vendor/simdjson/jsonexamples/small/jsoniter_scala/README.md +4 -0
- data/vendor/simdjson/scripts/dumpsimplestats.sh +11 -0
- data/vendor/simdjson/scripts/issue150.sh +14 -0
- data/vendor/simdjson/scripts/javascript/README.md +3 -0
- data/vendor/simdjson/scripts/javascript/generatelargejson.js +19 -0
- data/vendor/simdjson/scripts/minifier.sh +11 -0
- data/vendor/simdjson/scripts/parseandstat.sh +24 -0
- data/vendor/simdjson/scripts/parser.sh +11 -0
- data/vendor/simdjson/scripts/parsingcompdata.sh +26 -0
- data/vendor/simdjson/scripts/plotparse.sh +98 -0
- data/vendor/simdjson/scripts/selectparser.sh +11 -0
- data/vendor/simdjson/scripts/setupfortesting/disablehyperthreading.sh +15 -0
- data/vendor/simdjson/scripts/setupfortesting/powerpolicy.sh +32 -0
- data/vendor/simdjson/scripts/setupfortesting/setupfortesting.sh +6 -0
- data/vendor/simdjson/scripts/setupfortesting/turboboost.sh +51 -0
- data/vendor/simdjson/scripts/testjson2json.sh +99 -0
- data/vendor/simdjson/scripts/transitions/Makefile +10 -0
- data/vendor/simdjson/scripts/transitions/generatetransitions.cpp +20 -0
- data/vendor/simdjson/singleheader/README.md +1 -0
- data/vendor/simdjson/singleheader/amalgamation_demo.cpp +20 -0
- data/vendor/simdjson/singleheader/simdjson.cpp +1652 -0
- data/vendor/simdjson/singleheader/simdjson.h +39692 -0
- data/vendor/simdjson/src/CMakeLists.txt +67 -0
- data/vendor/simdjson/src/jsonioutil.cpp +35 -0
- data/vendor/simdjson/src/jsonminifier.cpp +285 -0
- data/vendor/simdjson/src/jsonparser.cpp +91 -0
- data/vendor/simdjson/src/parsedjson.cpp +323 -0
- data/vendor/simdjson/src/parsedjsoniterator.cpp +272 -0
- data/vendor/simdjson/src/simdjson.cpp +30 -0
- data/vendor/simdjson/src/stage1_find_marks.cpp +41 -0
- data/vendor/simdjson/src/stage2_build_tape.cpp +567 -0
- data/vendor/simdjson/style/clang-format-check.sh +25 -0
- data/vendor/simdjson/style/clang-format.sh +25 -0
- data/vendor/simdjson/style/run-clang-format.py +326 -0
- data/vendor/simdjson/tape.md +134 -0
- data/vendor/simdjson/tests/CMakeLists.txt +25 -0
- data/vendor/simdjson/tests/allparserscheckfile.cpp +192 -0
- data/vendor/simdjson/tests/basictests.cpp +75 -0
- data/vendor/simdjson/tests/jsoncheck.cpp +136 -0
- data/vendor/simdjson/tests/numberparsingcheck.cpp +224 -0
- data/vendor/simdjson/tests/pointercheck.cpp +38 -0
- data/vendor/simdjson/tests/singleheadertest.cpp +22 -0
- data/vendor/simdjson/tests/stringparsingcheck.cpp +408 -0
- data/vendor/simdjson/tools/CMakeLists.txt +3 -0
- data/vendor/simdjson/tools/cmake/FindCTargets.cmake +15 -0
- data/vendor/simdjson/tools/cmake/FindOptions.cmake +52 -0
- data/vendor/simdjson/tools/json2json.cpp +112 -0
- data/vendor/simdjson/tools/jsonpointer.cpp +93 -0
- data/vendor/simdjson/tools/jsonstats.cpp +143 -0
- data/vendor/simdjson/tools/minify.cpp +21 -0
- data/vendor/simdjson/tools/release.py +125 -0
- data/vendor/simdjson/windows/dirent_portable.h +1043 -0
- 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
|