simdjson 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|