From b39a9f52ed3f33082f13f51678d053ee80a2e1f4 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Fri, 29 Nov 2024 11:31:35 +0000 Subject: [Rework] Replace fastutf with simdutf Simdutf is faster and has way better support of the architectures (especially when it comes to non-x86 stuff). Hence, it is a good idea to use it instead of the non-supported fastutf8 stuff. --- CMakeLists.txt | 5 +- contrib/DEPENDENCY_INFO.md | 2 +- contrib/backward-cpp/CMakeLists.txt | 2 +- contrib/doctest/CMakeLists.txt | 2 +- contrib/fastutf8/CMakeLists.txt | 11 - contrib/fastutf8/LICENSE | 22 - contrib/fastutf8/avx2.c | 314 -- contrib/fastutf8/fastutf8.c | 160 - contrib/fastutf8/fastutf8.h | 65 - contrib/fastutf8/sse41.c | 272 -- contrib/simdutf/CMakeLists.txt | 114 + contrib/simdutf/LICENSE-APACHE | 201 ++ contrib/simdutf/cmake/CPM.cmake | 1161 ++++++ contrib/simdutf/cmake/JoinPaths.cmake | 23 + .../cmake/Toolchains/loongarch64-linux-gnu.cmake | 4 + .../cmake/Toolchains/riscv64-linux-gnu.cmake | 4 + contrib/simdutf/cmake/add_cpp_test.cmake | 63 + contrib/simdutf/cmake/simdutf-config.cmake.in | 2 + contrib/simdutf/cmake/simdutf-flags.cmake | 25 + contrib/simdutf/include/simdutf.h | 26 + contrib/simdutf/include/simdutf/avx512.h | 79 + contrib/simdutf/include/simdutf/common_defs.h | 151 + contrib/simdutf/include/simdutf/compiler_check.h | 45 + contrib/simdutf/include/simdutf/encoding_types.h | 43 + contrib/simdutf/include/simdutf/error.h | 69 + contrib/simdutf/include/simdutf/implementation.h | 3716 ++++++++++++++++++++ .../include/simdutf/internal/isadetection.h | 324 ++ contrib/simdutf/include/simdutf/portability.h | 262 ++ contrib/simdutf/include/simdutf/simdutf_version.h | 26 + contrib/simdutf/src/CMakeLists.txt | 46 + contrib/simdutf/src/arm64/arm_base64.cpp | 501 +++ .../src/arm64/arm_convert_latin1_to_utf16.cpp | 24 + .../src/arm64/arm_convert_latin1_to_utf32.cpp | 24 + .../src/arm64/arm_convert_latin1_to_utf8.cpp | 70 + .../src/arm64/arm_convert_utf16_to_latin1.cpp | 63 + .../src/arm64/arm_convert_utf16_to_utf32.cpp | 191 + .../src/arm64/arm_convert_utf16_to_utf8.cpp | 587 ++++ .../src/arm64/arm_convert_utf32_to_latin1.cpp | 60 + .../src/arm64/arm_convert_utf32_to_utf16.cpp | 151 + .../src/arm64/arm_convert_utf32_to_utf8.cpp | 505 +++ .../src/arm64/arm_convert_utf8_to_latin1.cpp | 69 + .../src/arm64/arm_convert_utf8_to_utf16.cpp | 288 ++ .../src/arm64/arm_convert_utf8_to_utf32.cpp | 179 + contrib/simdutf/src/arm64/arm_validate_utf16.cpp | 143 + contrib/simdutf/src/arm64/arm_validate_utf32le.cpp | 65 + contrib/simdutf/src/arm64/implementation.cpp | 1185 +++++++ contrib/simdutf/src/encoding_types.cpp | 75 + contrib/simdutf/src/error.cpp | 3 + contrib/simdutf/src/fallback/implementation.cpp | 691 ++++ contrib/simdutf/src/generic/buf_block_reader.h | 109 + contrib/simdutf/src/generic/utf16.h | 74 + contrib/simdutf/src/generic/utf8.h | 40 + .../src/generic/utf8_to_latin1/utf8_to_latin1.h | 315 ++ .../generic/utf8_to_latin1/valid_utf8_to_latin1.h | 80 + .../src/generic/utf8_to_utf16/utf8_to_utf16.h | 334 ++ .../generic/utf8_to_utf16/valid_utf8_to_utf16.h | 76 + .../src/generic/utf8_to_utf32/utf8_to_utf32.h | 320 ++ .../generic/utf8_to_utf32/valid_utf8_to_utf32.h | 44 + .../utf8_validation/utf8_lookup4_algorithm.h | 223 ++ .../src/generic/utf8_validation/utf8_validator.h | 138 + contrib/simdutf/src/haswell/avx2_base64.cpp | 577 +++ .../src/haswell/avx2_convert_latin1_to_utf16.cpp | 37 + .../src/haswell/avx2_convert_latin1_to_utf32.cpp | 20 + .../src/haswell/avx2_convert_latin1_to_utf8.cpp | 83 + .../src/haswell/avx2_convert_utf16_to_latin1.cpp | 85 + .../src/haswell/avx2_convert_utf16_to_utf32.cpp | 210 ++ .../src/haswell/avx2_convert_utf16_to_utf8.cpp | 602 ++++ .../src/haswell/avx2_convert_utf32_to_latin1.cpp | 93 + .../src/haswell/avx2_convert_utf32_to_utf16.cpp | 174 + .../src/haswell/avx2_convert_utf32_to_utf8.cpp | 569 +++ .../src/haswell/avx2_convert_utf8_to_latin1.cpp | 60 + .../src/haswell/avx2_convert_utf8_to_utf16.cpp | 195 + .../src/haswell/avx2_convert_utf8_to_utf32.cpp | 135 + .../simdutf/src/haswell/avx2_validate_utf16.cpp | 206 ++ .../simdutf/src/haswell/avx2_validate_utf32le.cpp | 70 + contrib/simdutf/src/haswell/implementation.cpp | 1145 ++++++ .../src/icelake/icelake_ascii_validation.inl.cpp | 19 + contrib/simdutf/src/icelake/icelake_base64.inl.cpp | 358 ++ .../icelake_convert_latin1_to_utf16.inl.cpp | 36 + .../icelake_convert_latin1_to_utf32.inl.cpp | 20 + .../icelake/icelake_convert_latin1_to_utf8.inl.cpp | 107 + .../icelake_convert_utf16_to_latin1.inl.cpp | 103 + .../icelake/icelake_convert_utf16_to_utf32.inl.cpp | 136 + .../icelake/icelake_convert_utf16_to_utf8.inl.cpp | 206 ++ .../icelake_convert_utf32_to_latin1.inl.cpp | 74 + .../icelake/icelake_convert_utf32_to_utf16.inl.cpp | 178 + .../icelake/icelake_convert_utf32_to_utf8.inl.cpp | 574 +++ .../icelake/icelake_convert_utf8_to_latin1.inl.cpp | 104 + .../icelake_convert_valid_utf8_to_latin1.inl.cpp | 69 + .../simdutf/src/icelake/icelake_from_utf8.inl.cpp | 338 ++ .../src/icelake/icelake_from_valid_utf8.inl.cpp | 136 + contrib/simdutf/src/icelake/icelake_macros.inl.cpp | 143 + .../src/icelake/icelake_utf32_validation.inl.cpp | 35 + .../src/icelake/icelake_utf8_common.inl.cpp | 796 +++++ .../src/icelake/icelake_utf8_validation.inl.cpp | 116 + contrib/simdutf/src/icelake/implementation.cpp | 1650 +++++++++ contrib/simdutf/src/implementation.cpp | 1991 +++++++++++ contrib/simdutf/src/lasx/implementation.cpp | 1298 +++++++ contrib/simdutf/src/lasx/lasx_base64.cpp | 596 ++++ .../src/lasx/lasx_convert_latin1_to_utf16.cpp | 76 + .../src/lasx/lasx_convert_latin1_to_utf32.cpp | 55 + .../src/lasx/lasx_convert_latin1_to_utf8.cpp | 65 + .../src/lasx/lasx_convert_utf16_to_latin1.cpp | 66 + .../src/lasx/lasx_convert_utf16_to_utf32.cpp | 195 + .../src/lasx/lasx_convert_utf16_to_utf8.cpp | 558 +++ .../src/lasx/lasx_convert_utf32_to_latin1.cpp | 73 + .../src/lasx/lasx_convert_utf32_to_utf16.cpp | 218 ++ .../src/lasx/lasx_convert_utf32_to_utf8.cpp | 589 ++++ .../src/lasx/lasx_convert_utf8_to_latin1.cpp | 72 + .../src/lasx/lasx_convert_utf8_to_utf16.cpp | 293 ++ .../src/lasx/lasx_convert_utf8_to_utf32.cpp | 193 + contrib/simdutf/src/lasx/lasx_validate_utf16.cpp | 201 ++ contrib/simdutf/src/lasx/lasx_validate_utf32le.cpp | 85 + contrib/simdutf/src/lsx/implementation.cpp | 1178 +++++++ contrib/simdutf/src/lsx/lsx_base64.cpp | 580 +++ .../src/lsx/lsx_convert_latin1_to_utf16.cpp | 39 + .../src/lsx/lsx_convert_latin1_to_utf32.cpp | 27 + .../simdutf/src/lsx/lsx_convert_latin1_to_utf8.cpp | 56 + .../src/lsx/lsx_convert_utf16_to_latin1.cpp | 66 + .../simdutf/src/lsx/lsx_convert_utf16_to_utf32.cpp | 139 + .../simdutf/src/lsx/lsx_convert_utf16_to_utf8.cpp | 526 +++ .../src/lsx/lsx_convert_utf32_to_latin1.cpp | 66 + .../simdutf/src/lsx/lsx_convert_utf32_to_utf16.cpp | 155 + .../simdutf/src/lsx/lsx_convert_utf32_to_utf8.cpp | 459 +++ .../simdutf/src/lsx/lsx_convert_utf8_to_latin1.cpp | 75 + .../simdutf/src/lsx/lsx_convert_utf8_to_utf16.cpp | 288 ++ .../simdutf/src/lsx/lsx_convert_utf8_to_utf32.cpp | 182 + contrib/simdutf/src/lsx/lsx_validate_utf16.cpp | 201 ++ contrib/simdutf/src/lsx/lsx_validate_utf32le.cpp | 69 + contrib/simdutf/src/ppc64/implementation.cpp | 510 +++ contrib/simdutf/src/rvv/implementation.cpp | 280 ++ contrib/simdutf/src/rvv/rvv_helpers.inl.cpp | 23 + contrib/simdutf/src/rvv/rvv_latin1_to.inl.cpp | 66 + contrib/simdutf/src/rvv/rvv_length_from.inl.cpp | 165 + contrib/simdutf/src/rvv/rvv_utf16_to.inl.cpp | 393 +++ contrib/simdutf/src/rvv/rvv_utf32_to.inl.cpp | 289 ++ contrib/simdutf/src/rvv/rvv_utf8_to.inl.cpp | 430 +++ contrib/simdutf/src/rvv/rvv_validate.inl.cpp | 228 ++ contrib/simdutf/src/scalar/ascii.h | 67 + contrib/simdutf/src/scalar/base64.h | 434 +++ contrib/simdutf/src/scalar/latin1.h | 32 + .../src/scalar/latin1_to_utf16/latin1_to_utf16.h | 49 + .../src/scalar/latin1_to_utf32/latin1_to_utf32.h | 23 + .../src/scalar/latin1_to_utf8/latin1_to_utf8.h | 104 + contrib/simdutf/src/scalar/utf16.h | 142 + .../src/scalar/utf16_to_latin1/utf16_to_latin1.h | 95 + .../scalar/utf16_to_latin1/valid_utf16_to_latin1.h | 31 + .../src/scalar/utf16_to_utf32/utf16_to_utf32.h | 87 + .../scalar/utf16_to_utf32/valid_utf16_to_utf32.h | 45 + .../src/scalar/utf16_to_utf8/utf16_to_utf8.h | 160 + .../src/scalar/utf16_to_utf8/valid_utf16_to_utf8.h | 83 + contrib/simdutf/src/scalar/utf32.h | 80 + .../src/scalar/utf32_to_latin1/utf32_to_latin1.h | 62 + .../scalar/utf32_to_latin1/valid_utf32_to_latin1.h | 49 + .../src/scalar/utf32_to_utf16/utf32_to_utf16.h | 85 + .../scalar/utf32_to_utf16/valid_utf32_to_utf16.h | 45 + .../src/scalar/utf32_to_utf8/utf32_to_utf8.h | 123 + .../src/scalar/utf32_to_utf8/valid_utf32_to_utf8.h | 66 + contrib/simdutf/src/scalar/utf8.h | 295 ++ .../src/scalar/utf8_to_latin1/utf8_to_latin1.h | 207 ++ .../scalar/utf8_to_latin1/valid_utf8_to_latin1.h | 78 + .../src/scalar/utf8_to_utf16/utf8_to_utf16.h | 326 ++ .../src/scalar/utf8_to_utf16/valid_utf8_to_utf16.h | 98 + .../src/scalar/utf8_to_utf32/utf8_to_utf32.h | 282 ++ .../src/scalar/utf8_to_utf32/valid_utf8_to_utf32.h | 75 + contrib/simdutf/src/simdutf.cpp | 82 + contrib/simdutf/src/simdutf/arm64.h | 43 + contrib/simdutf/src/simdutf/arm64/begin.h | 1 + .../simdutf/src/simdutf/arm64/bitmanipulation.h | 31 + contrib/simdutf/src/simdutf/arm64/end.h | 1 + contrib/simdutf/src/simdutf/arm64/implementation.h | 221 ++ contrib/simdutf/src/simdutf/arm64/intrinsics.h | 10 + contrib/simdutf/src/simdutf/arm64/simd.h | 725 ++++ contrib/simdutf/src/simdutf/arm64/simd16-inl.h | 407 +++ contrib/simdutf/src/simdutf/fallback.h | 42 + contrib/simdutf/src/simdutf/fallback/begin.h | 1 + .../simdutf/src/simdutf/fallback/bitmanipulation.h | 13 + contrib/simdutf/src/simdutf/fallback/end.h | 1 + .../simdutf/src/simdutf/fallback/implementation.h | 217 ++ contrib/simdutf/src/simdutf/haswell.h | 63 + contrib/simdutf/src/simdutf/haswell/begin.h | 14 + .../simdutf/src/simdutf/haswell/bitmanipulation.h | 33 + contrib/simdutf/src/simdutf/haswell/end.h | 12 + .../simdutf/src/simdutf/haswell/implementation.h | 226 ++ contrib/simdutf/src/simdutf/haswell/intrinsics.h | 62 + contrib/simdutf/src/simdutf/haswell/simd.h | 502 +++ contrib/simdutf/src/simdutf/haswell/simd16-inl.h | 355 ++ contrib/simdutf/src/simdutf/icelake.h | 71 + contrib/simdutf/src/simdutf/icelake/begin.h | 14 + .../simdutf/src/simdutf/icelake/bitmanipulation.h | 33 + contrib/simdutf/src/simdutf/icelake/end.h | 12 + .../simdutf/src/simdutf/icelake/implementation.h | 229 ++ contrib/simdutf/src/simdutf/icelake/intrinsics.h | 138 + contrib/simdutf/src/simdutf/lasx.h | 44 + contrib/simdutf/src/simdutf/lasx/begin.h | 1 + contrib/simdutf/src/simdutf/lasx/bitmanipulation.h | 25 + contrib/simdutf/src/simdutf/lasx/end.h | 1 + contrib/simdutf/src/simdutf/lasx/implementation.h | 230 ++ contrib/simdutf/src/simdutf/lasx/intrinsics.h | 101 + contrib/simdutf/src/simdutf/lasx/simd.h | 707 ++++ contrib/simdutf/src/simdutf/lasx/simd16-inl.h | 348 ++ contrib/simdutf/src/simdutf/lsx.h | 44 + contrib/simdutf/src/simdutf/lsx/begin.h | 1 + contrib/simdutf/src/simdutf/lsx/bitmanipulation.h | 25 + contrib/simdutf/src/simdutf/lsx/end.h | 1 + contrib/simdutf/src/simdutf/lsx/implementation.h | 229 ++ contrib/simdutf/src/simdutf/lsx/intrinsics.h | 10 + contrib/simdutf/src/simdutf/lsx/simd.h | 600 ++++ contrib/simdutf/src/simdutf/lsx/simd16-inl.h | 378 ++ contrib/simdutf/src/simdutf/ppc64.h | 40 + contrib/simdutf/src/simdutf/ppc64/begin.h | 1 + .../simdutf/src/simdutf/ppc64/bitmanipulation.h | 23 + contrib/simdutf/src/simdutf/ppc64/end.h | 1 + contrib/simdutf/src/simdutf/ppc64/implementation.h | 168 + contrib/simdutf/src/simdutf/ppc64/intrinsics.h | 19 + contrib/simdutf/src/simdutf/ppc64/simd.h | 479 +++ contrib/simdutf/src/simdutf/rvv.h | 41 + contrib/simdutf/src/simdutf/rvv/begin.h | 7 + contrib/simdutf/src/simdutf/rvv/end.h | 7 + contrib/simdutf/src/simdutf/rvv/implementation.h | 234 ++ contrib/simdutf/src/simdutf/rvv/intrinsics.h | 131 + contrib/simdutf/src/simdutf/westmere.h | 59 + contrib/simdutf/src/simdutf/westmere/begin.h | 7 + .../simdutf/src/simdutf/westmere/bitmanipulation.h | 35 + contrib/simdutf/src/simdutf/westmere/end.h | 7 + .../simdutf/src/simdutf/westmere/implementation.h | 222 ++ contrib/simdutf/src/simdutf/westmere/intrinsics.h | 38 + contrib/simdutf/src/simdutf/westmere/simd.h | 593 ++++ contrib/simdutf/src/simdutf/westmere/simd16-inl.h | 358 ++ contrib/simdutf/src/tables/base64_tables.h | 688 ++++ contrib/simdutf/src/tables/utf16_to_utf8_tables.h | 768 ++++ contrib/simdutf/src/tables/utf8_to_utf16_tables.h | 826 +++++ contrib/simdutf/src/westmere/implementation.cpp | 1142 ++++++ contrib/simdutf/src/westmere/internal/loader.cpp | 7 + .../internal/write_v_u16_11bits_to_utf8.cpp | 66 + contrib/simdutf/src/westmere/sse_base64.cpp | 591 ++++ .../src/westmere/sse_convert_latin1_to_utf16.cpp | 21 + .../src/westmere/sse_convert_latin1_to_utf32.cpp | 31 + .../src/westmere/sse_convert_latin1_to_utf8.cpp | 71 + .../src/westmere/sse_convert_utf16_to_latin1.cpp | 72 + .../src/westmere/sse_convert_utf16_to_utf32.cpp | 206 ++ .../src/westmere/sse_convert_utf16_to_utf8.cpp | 504 +++ .../src/westmere/sse_convert_utf32_to_latin1.cpp | 82 + .../src/westmere/sse_convert_utf32_to_utf16.cpp | 170 + .../src/westmere/sse_convert_utf32_to_utf8.cpp | 590 ++++ .../src/westmere/sse_convert_utf8_to_latin1.cpp | 58 + .../src/westmere/sse_convert_utf8_to_utf16.cpp | 197 ++ .../src/westmere/sse_convert_utf8_to_utf32.cpp | 141 + .../simdutf/src/westmere/sse_validate_utf16.cpp | 211 ++ .../simdutf/src/westmere/sse_validate_utf32le.cpp | 69 + src/CMakeLists.txt | 2 +- src/libmime/mime_encoding.c | 2 +- src/libmime/mime_parser.c | 2 +- src/libmime/mime_string.hxx | 8 +- src/libmime/scan_result.c | 2 +- src/libserver/cfg_utils.cxx | 10 +- src/libserver/maps/map_helpers.c | 4 +- src/libserver/protocol.c | 2 +- src/libserver/re_cache.c | 2 +- src/libutil/CMakeLists.txt | 1 + src/libutil/cxx/rspamd-simdutf.cxx | 41 + src/libutil/fstring.c | 2 +- src/libutil/regexp.c | 2 +- src/libutil/rspamd_simdutf.h | 34 + src/libutil/str_util.c | 2 +- src/lua/lua_text.c | 2 +- src/lua/lua_util.c | 2 +- 267 files changed, 54192 insertions(+), 875 deletions(-) delete mode 100644 contrib/fastutf8/CMakeLists.txt delete mode 100644 contrib/fastutf8/LICENSE delete mode 100644 contrib/fastutf8/avx2.c delete mode 100644 contrib/fastutf8/fastutf8.c delete mode 100644 contrib/fastutf8/fastutf8.h delete mode 100644 contrib/fastutf8/sse41.c create mode 100644 contrib/simdutf/CMakeLists.txt create mode 100644 contrib/simdutf/LICENSE-APACHE create mode 100644 contrib/simdutf/cmake/CPM.cmake create mode 100644 contrib/simdutf/cmake/JoinPaths.cmake create mode 100644 contrib/simdutf/cmake/Toolchains/loongarch64-linux-gnu.cmake create mode 100644 contrib/simdutf/cmake/Toolchains/riscv64-linux-gnu.cmake create mode 100644 contrib/simdutf/cmake/add_cpp_test.cmake create mode 100644 contrib/simdutf/cmake/simdutf-config.cmake.in create mode 100644 contrib/simdutf/cmake/simdutf-flags.cmake create mode 100644 contrib/simdutf/include/simdutf.h create mode 100644 contrib/simdutf/include/simdutf/avx512.h create mode 100644 contrib/simdutf/include/simdutf/common_defs.h create mode 100644 contrib/simdutf/include/simdutf/compiler_check.h create mode 100644 contrib/simdutf/include/simdutf/encoding_types.h create mode 100644 contrib/simdutf/include/simdutf/error.h create mode 100644 contrib/simdutf/include/simdutf/implementation.h create mode 100644 contrib/simdutf/include/simdutf/internal/isadetection.h create mode 100644 contrib/simdutf/include/simdutf/portability.h create mode 100644 contrib/simdutf/include/simdutf/simdutf_version.h create mode 100644 contrib/simdutf/src/CMakeLists.txt create mode 100644 contrib/simdutf/src/arm64/arm_base64.cpp create mode 100644 contrib/simdutf/src/arm64/arm_convert_latin1_to_utf16.cpp create mode 100644 contrib/simdutf/src/arm64/arm_convert_latin1_to_utf32.cpp create mode 100644 contrib/simdutf/src/arm64/arm_convert_latin1_to_utf8.cpp create mode 100644 contrib/simdutf/src/arm64/arm_convert_utf16_to_latin1.cpp create mode 100644 contrib/simdutf/src/arm64/arm_convert_utf16_to_utf32.cpp create mode 100644 contrib/simdutf/src/arm64/arm_convert_utf16_to_utf8.cpp create mode 100644 contrib/simdutf/src/arm64/arm_convert_utf32_to_latin1.cpp create mode 100644 contrib/simdutf/src/arm64/arm_convert_utf32_to_utf16.cpp create mode 100644 contrib/simdutf/src/arm64/arm_convert_utf32_to_utf8.cpp create mode 100644 contrib/simdutf/src/arm64/arm_convert_utf8_to_latin1.cpp create mode 100644 contrib/simdutf/src/arm64/arm_convert_utf8_to_utf16.cpp create mode 100644 contrib/simdutf/src/arm64/arm_convert_utf8_to_utf32.cpp create mode 100644 contrib/simdutf/src/arm64/arm_validate_utf16.cpp create mode 100644 contrib/simdutf/src/arm64/arm_validate_utf32le.cpp create mode 100644 contrib/simdutf/src/arm64/implementation.cpp create mode 100644 contrib/simdutf/src/encoding_types.cpp create mode 100644 contrib/simdutf/src/error.cpp create mode 100644 contrib/simdutf/src/fallback/implementation.cpp create mode 100644 contrib/simdutf/src/generic/buf_block_reader.h create mode 100644 contrib/simdutf/src/generic/utf16.h create mode 100644 contrib/simdutf/src/generic/utf8.h create mode 100644 contrib/simdutf/src/generic/utf8_to_latin1/utf8_to_latin1.h create mode 100644 contrib/simdutf/src/generic/utf8_to_latin1/valid_utf8_to_latin1.h create mode 100644 contrib/simdutf/src/generic/utf8_to_utf16/utf8_to_utf16.h create mode 100644 contrib/simdutf/src/generic/utf8_to_utf16/valid_utf8_to_utf16.h create mode 100644 contrib/simdutf/src/generic/utf8_to_utf32/utf8_to_utf32.h create mode 100644 contrib/simdutf/src/generic/utf8_to_utf32/valid_utf8_to_utf32.h create mode 100644 contrib/simdutf/src/generic/utf8_validation/utf8_lookup4_algorithm.h create mode 100644 contrib/simdutf/src/generic/utf8_validation/utf8_validator.h create mode 100644 contrib/simdutf/src/haswell/avx2_base64.cpp create mode 100644 contrib/simdutf/src/haswell/avx2_convert_latin1_to_utf16.cpp create mode 100644 contrib/simdutf/src/haswell/avx2_convert_latin1_to_utf32.cpp create mode 100644 contrib/simdutf/src/haswell/avx2_convert_latin1_to_utf8.cpp create mode 100644 contrib/simdutf/src/haswell/avx2_convert_utf16_to_latin1.cpp create mode 100644 contrib/simdutf/src/haswell/avx2_convert_utf16_to_utf32.cpp create mode 100644 contrib/simdutf/src/haswell/avx2_convert_utf16_to_utf8.cpp create mode 100644 contrib/simdutf/src/haswell/avx2_convert_utf32_to_latin1.cpp create mode 100644 contrib/simdutf/src/haswell/avx2_convert_utf32_to_utf16.cpp create mode 100644 contrib/simdutf/src/haswell/avx2_convert_utf32_to_utf8.cpp create mode 100644 contrib/simdutf/src/haswell/avx2_convert_utf8_to_latin1.cpp create mode 100644 contrib/simdutf/src/haswell/avx2_convert_utf8_to_utf16.cpp create mode 100644 contrib/simdutf/src/haswell/avx2_convert_utf8_to_utf32.cpp create mode 100644 contrib/simdutf/src/haswell/avx2_validate_utf16.cpp create mode 100644 contrib/simdutf/src/haswell/avx2_validate_utf32le.cpp create mode 100644 contrib/simdutf/src/haswell/implementation.cpp create mode 100644 contrib/simdutf/src/icelake/icelake_ascii_validation.inl.cpp create mode 100644 contrib/simdutf/src/icelake/icelake_base64.inl.cpp create mode 100644 contrib/simdutf/src/icelake/icelake_convert_latin1_to_utf16.inl.cpp create mode 100644 contrib/simdutf/src/icelake/icelake_convert_latin1_to_utf32.inl.cpp create mode 100644 contrib/simdutf/src/icelake/icelake_convert_latin1_to_utf8.inl.cpp create mode 100644 contrib/simdutf/src/icelake/icelake_convert_utf16_to_latin1.inl.cpp create mode 100644 contrib/simdutf/src/icelake/icelake_convert_utf16_to_utf32.inl.cpp create mode 100644 contrib/simdutf/src/icelake/icelake_convert_utf16_to_utf8.inl.cpp create mode 100644 contrib/simdutf/src/icelake/icelake_convert_utf32_to_latin1.inl.cpp create mode 100644 contrib/simdutf/src/icelake/icelake_convert_utf32_to_utf16.inl.cpp create mode 100644 contrib/simdutf/src/icelake/icelake_convert_utf32_to_utf8.inl.cpp create mode 100644 contrib/simdutf/src/icelake/icelake_convert_utf8_to_latin1.inl.cpp create mode 100644 contrib/simdutf/src/icelake/icelake_convert_valid_utf8_to_latin1.inl.cpp create mode 100644 contrib/simdutf/src/icelake/icelake_from_utf8.inl.cpp create mode 100644 contrib/simdutf/src/icelake/icelake_from_valid_utf8.inl.cpp create mode 100644 contrib/simdutf/src/icelake/icelake_macros.inl.cpp create mode 100644 contrib/simdutf/src/icelake/icelake_utf32_validation.inl.cpp create mode 100644 contrib/simdutf/src/icelake/icelake_utf8_common.inl.cpp create mode 100644 contrib/simdutf/src/icelake/icelake_utf8_validation.inl.cpp create mode 100644 contrib/simdutf/src/icelake/implementation.cpp create mode 100644 contrib/simdutf/src/implementation.cpp create mode 100644 contrib/simdutf/src/lasx/implementation.cpp create mode 100644 contrib/simdutf/src/lasx/lasx_base64.cpp create mode 100644 contrib/simdutf/src/lasx/lasx_convert_latin1_to_utf16.cpp create mode 100644 contrib/simdutf/src/lasx/lasx_convert_latin1_to_utf32.cpp create mode 100644 contrib/simdutf/src/lasx/lasx_convert_latin1_to_utf8.cpp create mode 100644 contrib/simdutf/src/lasx/lasx_convert_utf16_to_latin1.cpp create mode 100644 contrib/simdutf/src/lasx/lasx_convert_utf16_to_utf32.cpp create mode 100644 contrib/simdutf/src/lasx/lasx_convert_utf16_to_utf8.cpp create mode 100644 contrib/simdutf/src/lasx/lasx_convert_utf32_to_latin1.cpp create mode 100644 contrib/simdutf/src/lasx/lasx_convert_utf32_to_utf16.cpp create mode 100644 contrib/simdutf/src/lasx/lasx_convert_utf32_to_utf8.cpp create mode 100644 contrib/simdutf/src/lasx/lasx_convert_utf8_to_latin1.cpp create mode 100644 contrib/simdutf/src/lasx/lasx_convert_utf8_to_utf16.cpp create mode 100644 contrib/simdutf/src/lasx/lasx_convert_utf8_to_utf32.cpp create mode 100644 contrib/simdutf/src/lasx/lasx_validate_utf16.cpp create mode 100644 contrib/simdutf/src/lasx/lasx_validate_utf32le.cpp create mode 100644 contrib/simdutf/src/lsx/implementation.cpp create mode 100644 contrib/simdutf/src/lsx/lsx_base64.cpp create mode 100644 contrib/simdutf/src/lsx/lsx_convert_latin1_to_utf16.cpp create mode 100644 contrib/simdutf/src/lsx/lsx_convert_latin1_to_utf32.cpp create mode 100644 contrib/simdutf/src/lsx/lsx_convert_latin1_to_utf8.cpp create mode 100644 contrib/simdutf/src/lsx/lsx_convert_utf16_to_latin1.cpp create mode 100644 contrib/simdutf/src/lsx/lsx_convert_utf16_to_utf32.cpp create mode 100644 contrib/simdutf/src/lsx/lsx_convert_utf16_to_utf8.cpp create mode 100644 contrib/simdutf/src/lsx/lsx_convert_utf32_to_latin1.cpp create mode 100644 contrib/simdutf/src/lsx/lsx_convert_utf32_to_utf16.cpp create mode 100644 contrib/simdutf/src/lsx/lsx_convert_utf32_to_utf8.cpp create mode 100644 contrib/simdutf/src/lsx/lsx_convert_utf8_to_latin1.cpp create mode 100644 contrib/simdutf/src/lsx/lsx_convert_utf8_to_utf16.cpp create mode 100644 contrib/simdutf/src/lsx/lsx_convert_utf8_to_utf32.cpp create mode 100644 contrib/simdutf/src/lsx/lsx_validate_utf16.cpp create mode 100644 contrib/simdutf/src/lsx/lsx_validate_utf32le.cpp create mode 100644 contrib/simdutf/src/ppc64/implementation.cpp create mode 100644 contrib/simdutf/src/rvv/implementation.cpp create mode 100644 contrib/simdutf/src/rvv/rvv_helpers.inl.cpp create mode 100644 contrib/simdutf/src/rvv/rvv_latin1_to.inl.cpp create mode 100644 contrib/simdutf/src/rvv/rvv_length_from.inl.cpp create mode 100644 contrib/simdutf/src/rvv/rvv_utf16_to.inl.cpp create mode 100644 contrib/simdutf/src/rvv/rvv_utf32_to.inl.cpp create mode 100644 contrib/simdutf/src/rvv/rvv_utf8_to.inl.cpp create mode 100644 contrib/simdutf/src/rvv/rvv_validate.inl.cpp create mode 100644 contrib/simdutf/src/scalar/ascii.h create mode 100644 contrib/simdutf/src/scalar/base64.h create mode 100644 contrib/simdutf/src/scalar/latin1.h create mode 100644 contrib/simdutf/src/scalar/latin1_to_utf16/latin1_to_utf16.h create mode 100644 contrib/simdutf/src/scalar/latin1_to_utf32/latin1_to_utf32.h create mode 100644 contrib/simdutf/src/scalar/latin1_to_utf8/latin1_to_utf8.h create mode 100644 contrib/simdutf/src/scalar/utf16.h create mode 100644 contrib/simdutf/src/scalar/utf16_to_latin1/utf16_to_latin1.h create mode 100644 contrib/simdutf/src/scalar/utf16_to_latin1/valid_utf16_to_latin1.h create mode 100644 contrib/simdutf/src/scalar/utf16_to_utf32/utf16_to_utf32.h create mode 100644 contrib/simdutf/src/scalar/utf16_to_utf32/valid_utf16_to_utf32.h create mode 100644 contrib/simdutf/src/scalar/utf16_to_utf8/utf16_to_utf8.h create mode 100644 contrib/simdutf/src/scalar/utf16_to_utf8/valid_utf16_to_utf8.h create mode 100644 contrib/simdutf/src/scalar/utf32.h create mode 100644 contrib/simdutf/src/scalar/utf32_to_latin1/utf32_to_latin1.h create mode 100644 contrib/simdutf/src/scalar/utf32_to_latin1/valid_utf32_to_latin1.h create mode 100644 contrib/simdutf/src/scalar/utf32_to_utf16/utf32_to_utf16.h create mode 100644 contrib/simdutf/src/scalar/utf32_to_utf16/valid_utf32_to_utf16.h create mode 100644 contrib/simdutf/src/scalar/utf32_to_utf8/utf32_to_utf8.h create mode 100644 contrib/simdutf/src/scalar/utf32_to_utf8/valid_utf32_to_utf8.h create mode 100644 contrib/simdutf/src/scalar/utf8.h create mode 100644 contrib/simdutf/src/scalar/utf8_to_latin1/utf8_to_latin1.h create mode 100644 contrib/simdutf/src/scalar/utf8_to_latin1/valid_utf8_to_latin1.h create mode 100644 contrib/simdutf/src/scalar/utf8_to_utf16/utf8_to_utf16.h create mode 100644 contrib/simdutf/src/scalar/utf8_to_utf16/valid_utf8_to_utf16.h create mode 100644 contrib/simdutf/src/scalar/utf8_to_utf32/utf8_to_utf32.h create mode 100644 contrib/simdutf/src/scalar/utf8_to_utf32/valid_utf8_to_utf32.h create mode 100644 contrib/simdutf/src/simdutf.cpp create mode 100644 contrib/simdutf/src/simdutf/arm64.h create mode 100644 contrib/simdutf/src/simdutf/arm64/begin.h create mode 100644 contrib/simdutf/src/simdutf/arm64/bitmanipulation.h create mode 100644 contrib/simdutf/src/simdutf/arm64/end.h create mode 100644 contrib/simdutf/src/simdutf/arm64/implementation.h create mode 100644 contrib/simdutf/src/simdutf/arm64/intrinsics.h create mode 100644 contrib/simdutf/src/simdutf/arm64/simd.h create mode 100644 contrib/simdutf/src/simdutf/arm64/simd16-inl.h create mode 100644 contrib/simdutf/src/simdutf/fallback.h create mode 100644 contrib/simdutf/src/simdutf/fallback/begin.h create mode 100644 contrib/simdutf/src/simdutf/fallback/bitmanipulation.h create mode 100644 contrib/simdutf/src/simdutf/fallback/end.h create mode 100644 contrib/simdutf/src/simdutf/fallback/implementation.h create mode 100644 contrib/simdutf/src/simdutf/haswell.h create mode 100644 contrib/simdutf/src/simdutf/haswell/begin.h create mode 100644 contrib/simdutf/src/simdutf/haswell/bitmanipulation.h create mode 100644 contrib/simdutf/src/simdutf/haswell/end.h create mode 100644 contrib/simdutf/src/simdutf/haswell/implementation.h create mode 100644 contrib/simdutf/src/simdutf/haswell/intrinsics.h create mode 100644 contrib/simdutf/src/simdutf/haswell/simd.h create mode 100644 contrib/simdutf/src/simdutf/haswell/simd16-inl.h create mode 100644 contrib/simdutf/src/simdutf/icelake.h create mode 100644 contrib/simdutf/src/simdutf/icelake/begin.h create mode 100644 contrib/simdutf/src/simdutf/icelake/bitmanipulation.h create mode 100644 contrib/simdutf/src/simdutf/icelake/end.h create mode 100644 contrib/simdutf/src/simdutf/icelake/implementation.h create mode 100644 contrib/simdutf/src/simdutf/icelake/intrinsics.h create mode 100644 contrib/simdutf/src/simdutf/lasx.h create mode 100644 contrib/simdutf/src/simdutf/lasx/begin.h create mode 100644 contrib/simdutf/src/simdutf/lasx/bitmanipulation.h create mode 100644 contrib/simdutf/src/simdutf/lasx/end.h create mode 100644 contrib/simdutf/src/simdutf/lasx/implementation.h create mode 100644 contrib/simdutf/src/simdutf/lasx/intrinsics.h create mode 100644 contrib/simdutf/src/simdutf/lasx/simd.h create mode 100644 contrib/simdutf/src/simdutf/lasx/simd16-inl.h create mode 100644 contrib/simdutf/src/simdutf/lsx.h create mode 100644 contrib/simdutf/src/simdutf/lsx/begin.h create mode 100644 contrib/simdutf/src/simdutf/lsx/bitmanipulation.h create mode 100644 contrib/simdutf/src/simdutf/lsx/end.h create mode 100644 contrib/simdutf/src/simdutf/lsx/implementation.h create mode 100644 contrib/simdutf/src/simdutf/lsx/intrinsics.h create mode 100644 contrib/simdutf/src/simdutf/lsx/simd.h create mode 100644 contrib/simdutf/src/simdutf/lsx/simd16-inl.h create mode 100644 contrib/simdutf/src/simdutf/ppc64.h create mode 100644 contrib/simdutf/src/simdutf/ppc64/begin.h create mode 100644 contrib/simdutf/src/simdutf/ppc64/bitmanipulation.h create mode 100644 contrib/simdutf/src/simdutf/ppc64/end.h create mode 100644 contrib/simdutf/src/simdutf/ppc64/implementation.h create mode 100644 contrib/simdutf/src/simdutf/ppc64/intrinsics.h create mode 100644 contrib/simdutf/src/simdutf/ppc64/simd.h create mode 100644 contrib/simdutf/src/simdutf/rvv.h create mode 100644 contrib/simdutf/src/simdutf/rvv/begin.h create mode 100644 contrib/simdutf/src/simdutf/rvv/end.h create mode 100644 contrib/simdutf/src/simdutf/rvv/implementation.h create mode 100644 contrib/simdutf/src/simdutf/rvv/intrinsics.h create mode 100644 contrib/simdutf/src/simdutf/westmere.h create mode 100644 contrib/simdutf/src/simdutf/westmere/begin.h create mode 100644 contrib/simdutf/src/simdutf/westmere/bitmanipulation.h create mode 100644 contrib/simdutf/src/simdutf/westmere/end.h create mode 100644 contrib/simdutf/src/simdutf/westmere/implementation.h create mode 100644 contrib/simdutf/src/simdutf/westmere/intrinsics.h create mode 100644 contrib/simdutf/src/simdutf/westmere/simd.h create mode 100644 contrib/simdutf/src/simdutf/westmere/simd16-inl.h create mode 100644 contrib/simdutf/src/tables/base64_tables.h create mode 100644 contrib/simdutf/src/tables/utf16_to_utf8_tables.h create mode 100644 contrib/simdutf/src/tables/utf8_to_utf16_tables.h create mode 100644 contrib/simdutf/src/westmere/implementation.cpp create mode 100644 contrib/simdutf/src/westmere/internal/loader.cpp create mode 100644 contrib/simdutf/src/westmere/internal/write_v_u16_11bits_to_utf8.cpp create mode 100644 contrib/simdutf/src/westmere/sse_base64.cpp create mode 100644 contrib/simdutf/src/westmere/sse_convert_latin1_to_utf16.cpp create mode 100644 contrib/simdutf/src/westmere/sse_convert_latin1_to_utf32.cpp create mode 100644 contrib/simdutf/src/westmere/sse_convert_latin1_to_utf8.cpp create mode 100644 contrib/simdutf/src/westmere/sse_convert_utf16_to_latin1.cpp create mode 100644 contrib/simdutf/src/westmere/sse_convert_utf16_to_utf32.cpp create mode 100644 contrib/simdutf/src/westmere/sse_convert_utf16_to_utf8.cpp create mode 100644 contrib/simdutf/src/westmere/sse_convert_utf32_to_latin1.cpp create mode 100644 contrib/simdutf/src/westmere/sse_convert_utf32_to_utf16.cpp create mode 100644 contrib/simdutf/src/westmere/sse_convert_utf32_to_utf8.cpp create mode 100644 contrib/simdutf/src/westmere/sse_convert_utf8_to_latin1.cpp create mode 100644 contrib/simdutf/src/westmere/sse_convert_utf8_to_utf16.cpp create mode 100644 contrib/simdutf/src/westmere/sse_convert_utf8_to_utf32.cpp create mode 100644 contrib/simdutf/src/westmere/sse_validate_utf16.cpp create mode 100644 contrib/simdutf/src/westmere/sse_validate_utf32le.cpp create mode 100644 src/libutil/cxx/rspamd-simdutf.cxx create mode 100644 src/libutil/rspamd_simdutf.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 21ad6241e..6b8a80e8e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ # ############################# INITIAL SECTION ############################################# -CMAKE_MINIMUM_REQUIRED(VERSION 3.12 FATAL_ERROR) +CMAKE_MINIMUM_REQUIRED(VERSION 3.15 FATAL_ERROR) SET(RSPAMD_VERSION_MAJOR 3) SET(RSPAMD_VERSION_MINOR 11) @@ -621,6 +621,8 @@ ADD_SUBDIRECTORY(contrib/http-parser) ADD_SUBDIRECTORY(contrib/fpconv) ADD_SUBDIRECTORY(contrib/lc-btrie) ADD_SUBDIRECTORY(contrib/libottery) +ADD_SUBDIRECTORY(contrib/simdutf) +INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/contrib/simdutf/include") IF (SYSTEM_ZSTD MATCHES "OFF") ADD_SUBDIRECTORY(contrib/zstd) ELSE () @@ -639,7 +641,6 @@ ADD_SUBDIRECTORY(contrib/lua-lpeg) ADD_SUBDIRECTORY(contrib/t1ha) ADD_SUBDIRECTORY(contrib/libev) ADD_SUBDIRECTORY(contrib/kann) -ADD_SUBDIRECTORY(contrib/fastutf8) ADD_SUBDIRECTORY(contrib/google-ced) IF (ENABLE_BACKWARD MATCHES "ON") ADD_SUBDIRECTORY(contrib/backward-cpp) diff --git a/contrib/DEPENDENCY_INFO.md b/contrib/DEPENDENCY_INFO.md index 86598129c..fc41c07a3 100644 --- a/contrib/DEPENDENCY_INFO.md +++ b/contrib/DEPENDENCY_INFO.md @@ -29,7 +29,7 @@ | google-ced | 37529e6 | Apache 2 | YES | build fixes | | kann | ? | MIT | YES | blas/lapack changes | | fpconv | ? | Boost | YES | many changes | -| fastutf8 | ? | MIT | YES | many changes | +| simdutf | ef7d39c | Apache 2 | NO | build system only | | expected | v1.0 | Public Domain / CC0 | NO | | | frozen | 1.0.1 | Apache 2 | NO | | | fmt | 11.0.0 | MIT | NO | | diff --git a/contrib/backward-cpp/CMakeLists.txt b/contrib/backward-cpp/CMakeLists.txt index 038c50516..9aa7bb13d 100644 --- a/contrib/backward-cpp/CMakeLists.txt +++ b/contrib/backward-cpp/CMakeLists.txt @@ -20,7 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.15) project(backward CXX) # Introduce variables: diff --git a/contrib/doctest/CMakeLists.txt b/contrib/doctest/CMakeLists.txt index c6b3f48ee..f85d74728 100644 --- a/contrib/doctest/CMakeLists.txt +++ b/contrib/doctest/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.15) if(POLICY CMP0077) cmake_policy(SET CMP0077 NEW) diff --git a/contrib/fastutf8/CMakeLists.txt b/contrib/fastutf8/CMakeLists.txt deleted file mode 100644 index 2a98ed815..000000000 --- a/contrib/fastutf8/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -SET(UTFSRC ${CMAKE_CURRENT_SOURCE_DIR}/fastutf8.c) -IF(HAVE_AVX2 AND "${ARCH}" STREQUAL "x86_64") - SET(UTFSRC ${UTFSRC} ${CMAKE_CURRENT_SOURCE_DIR}/avx2.c) - MESSAGE(STATUS "UTF8: AVX2 support is added") -ENDIF() -IF(HAVE_SSE41 AND "${ARCH}" STREQUAL "x86_64") - SET(UTFSRC ${UTFSRC} ${CMAKE_CURRENT_SOURCE_DIR}/sse41.c) - MESSAGE(STATUS "UTF8: SSE41 support is added") -ENDIF() - -ADD_LIBRARY(rspamd-fastutf8 STATIC ${UTFSRC}) \ No newline at end of file diff --git a/contrib/fastutf8/LICENSE b/contrib/fastutf8/LICENSE deleted file mode 100644 index 9b5471be2..000000000 --- a/contrib/fastutf8/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -MIT License - -Copyright (c) 2019 Yibo Cai -Copyright (c) 2019 Vsevolod Stakhov - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/contrib/fastutf8/avx2.c b/contrib/fastutf8/avx2.c deleted file mode 100644 index 765c62fdb..000000000 --- a/contrib/fastutf8/avx2.c +++ /dev/null @@ -1,314 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Yibo Cai - * Copyright (c) 2019 Vsevolod Stakhov - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "config.h" -#include "fastutf8.h" -#include "platform_config.h" - - -#ifndef __clang__ -#pragma GCC push_options -#pragma GCC target("avx2") -#endif - -#ifndef __SSE2__ -#define __SSE2__ -#endif -#ifndef __SSE__ -#define __SSE__ -#endif -#ifndef __SSE4_2__ -#define __SSE4_2__ -#endif -#ifndef __SSE4_1__ -#define __SSE4_1__ -#endif -#ifndef __SSEE3__ -#define __SSEE3__ -#endif -#ifndef __AVX__ -#define __AVX__ -#endif -#ifndef __AVX2__ -#define __AVX2__ -#endif - -#include - -/* - * Map high nibble of "First Byte" to legal character length minus 1 - * 0x00 ~ 0xBF --> 0 - * 0xC0 ~ 0xDF --> 1 - * 0xE0 ~ 0xEF --> 2 - * 0xF0 ~ 0xFF --> 3 - */ -static const int8_t _first_len_tbl[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, -}; - -/* Map "First Byte" to 8-th item of range table (0xC2 ~ 0xF4) */ -static const int8_t _first_range_tbl[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, -}; - -/* - * Range table, map range index to min and max values - * Index 0 : 00 ~ 7F (First Byte, ascii) - * Index 1,2,3: 80 ~ BF (Second, Third, Fourth Byte) - * Index 4 : A0 ~ BF (Second Byte after E0) - * Index 5 : 80 ~ 9F (Second Byte after ED) - * Index 6 : 90 ~ BF (Second Byte after F0) - * Index 7 : 80 ~ 8F (Second Byte after F4) - * Index 8 : C2 ~ F4 (First Byte, non ascii) - * Index 9~15 : illegal: i >= 127 && i <= -128 - */ -static const int8_t _range_min_tbl[] = { - 0x00, 0x80, 0x80, 0x80, 0xA0, 0x80, 0x90, 0x80, - 0xC2, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, - 0x00, 0x80, 0x80, 0x80, 0xA0, 0x80, 0x90, 0x80, - 0xC2, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, -}; -static const int8_t _range_max_tbl[] = { - 0x7F, 0xBF, 0xBF, 0xBF, 0xBF, 0x9F, 0xBF, 0x8F, - 0xF4, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x7F, 0xBF, 0xBF, 0xBF, 0xBF, 0x9F, 0xBF, 0x8F, - 0xF4, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -}; - -/* - * Tables for fast handling of four special First Bytes(E0,ED,F0,F4), after - * which the Second Byte are not 80~BF. It contains "range index adjustment". - * +------------+---------------+------------------+----------------+ - * | First Byte | original range| range adjustment | adjusted range | - * +------------+---------------+------------------+----------------+ - * | E0 | 2 | 2 | 4 | - * +------------+---------------+------------------+----------------+ - * | ED | 2 | 3 | 5 | - * +------------+---------------+------------------+----------------+ - * | F0 | 3 | 3 | 6 | - * +------------+---------------+------------------+----------------+ - * | F4 | 4 | 4 | 8 | - * +------------+---------------+------------------+----------------+ - */ -/* index1 -> E0, index14 -> ED */ -static const int8_t _df_ee_tbl[] = { - 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, - 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, -}; -/* index1 -> F0, index5 -> F4 */ -static const int8_t _ef_fe_tbl[] = { - 0, 3, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -static inline __m256i push_last_byte_of_a_to_b(__m256i a, __m256i b) - __attribute__((__target__("avx2"))); -static inline __m256i push_last_byte_of_a_to_b(__m256i a, __m256i b) -{ - return _mm256_alignr_epi8(b, _mm256_permute2x128_si256(a, b, 0x21), 15); -} - -static inline __m256i push_last_2bytes_of_a_to_b(__m256i a, __m256i b) - __attribute__((__target__("avx2"))); -static inline __m256i push_last_2bytes_of_a_to_b(__m256i a, __m256i b) -{ - return _mm256_alignr_epi8(b, _mm256_permute2x128_si256(a, b, 0x21), 14); -} - -static inline __m256i push_last_3bytes_of_a_to_b(__m256i a, __m256i b) - __attribute__((__target__("avx2"))); -static inline __m256i push_last_3bytes_of_a_to_b(__m256i a, __m256i b) -{ - return _mm256_alignr_epi8(b, _mm256_permute2x128_si256(a, b, 0x21), 13); -} - -off_t rspamd_fast_utf8_validate_avx2 (const unsigned char *data, size_t len) - __attribute__((__target__("avx2"))); - -/* 5x faster than naive method */ -/* Return 0 - success, -1 - error, >0 - first error char(if RET_ERR_IDX = 1) */ -off_t rspamd_fast_utf8_validate_avx2 (const unsigned char *data, size_t len) -{ - off_t err_pos = 1; - - if (len >= 32) { - __m256i prev_input = _mm256_set1_epi8 (0); - __m256i prev_first_len = _mm256_set1_epi8 (0); - - /* Cached tables */ - const __m256i first_len_tbl = - _mm256_lddqu_si256 ((const __m256i *) _first_len_tbl); - const __m256i first_range_tbl = - _mm256_lddqu_si256 ((const __m256i *) _first_range_tbl); - const __m256i range_min_tbl = - _mm256_lddqu_si256 ((const __m256i *) _range_min_tbl); - const __m256i range_max_tbl = - _mm256_lddqu_si256 ((const __m256i *) _range_max_tbl); - const __m256i df_ee_tbl = - _mm256_lddqu_si256 ((const __m256i *) _df_ee_tbl); - const __m256i ef_fe_tbl = - _mm256_lddqu_si256 ((const __m256i *) _ef_fe_tbl); - - __m256i error = _mm256_set1_epi8 (0); - - while (len >= 32) { - const __m256i input = _mm256_lddqu_si256 ((const __m256i *) data); - - /* high_nibbles = input >> 4 */ - const __m256i high_nibbles = - _mm256_and_si256 (_mm256_srli_epi16 (input, 4), _mm256_set1_epi8 (0x0F)); - - /* first_len = legal character length minus 1 */ - /* 0 for 00~7F, 1 for C0~DF, 2 for E0~EF, 3 for F0~FF */ - /* first_len = first_len_tbl[high_nibbles] */ - __m256i first_len = _mm256_shuffle_epi8 (first_len_tbl, high_nibbles); - - /* First Byte: set range index to 8 for bytes within 0xC0 ~ 0xFF */ - /* range = first_range_tbl[high_nibbles] */ - __m256i range = _mm256_shuffle_epi8 (first_range_tbl, high_nibbles); - - /* Second Byte: set range index to first_len */ - /* 0 for 00~7F, 1 for C0~DF, 2 for E0~EF, 3 for F0~FF */ - /* range |= (first_len, prev_first_len) << 1 byte */ - range = _mm256_or_si256 ( - range, push_last_byte_of_a_to_b (prev_first_len, first_len)); - - /* Third Byte: set range index to saturate_sub(first_len, 1) */ - /* 0 for 00~7F, 0 for C0~DF, 1 for E0~EF, 2 for F0~FF */ - __m256i tmp1, tmp2; - - /* tmp1 = saturate_sub(first_len, 1) */ - tmp1 = _mm256_subs_epu8 (first_len, _mm256_set1_epi8 (1)); - /* tmp2 = saturate_sub(prev_first_len, 1) */ - tmp2 = _mm256_subs_epu8 (prev_first_len, _mm256_set1_epi8 (1)); - - /* range |= (tmp1, tmp2) << 2 bytes */ - range = _mm256_or_si256 (range, push_last_2bytes_of_a_to_b (tmp2, tmp1)); - - /* Fourth Byte: set range index to saturate_sub(first_len, 2) */ - /* 0 for 00~7F, 0 for C0~DF, 0 for E0~EF, 1 for F0~FF */ - /* tmp1 = saturate_sub(first_len, 2) */ - tmp1 = _mm256_subs_epu8 (first_len, _mm256_set1_epi8 (2)); - /* tmp2 = saturate_sub(prev_first_len, 2) */ - tmp2 = _mm256_subs_epu8 (prev_first_len, _mm256_set1_epi8 (2)); - /* range |= (tmp1, tmp2) << 3 bytes */ - range = _mm256_or_si256 (range, push_last_3bytes_of_a_to_b (tmp2, tmp1)); - - /* - * Now we have below range indices caluclated - * Correct cases: - * - 8 for C0~FF - * - 3 for 1st byte after F0~FF - * - 2 for 1st byte after E0~EF or 2nd byte after F0~FF - * - 1 for 1st byte after C0~DF or 2nd byte after E0~EF or - * 3rd byte after F0~FF - * - 0 for others - * Error cases: - * 9,10,11 if non ascii First Byte overlaps - * E.g., F1 80 C2 90 --> 8 3 10 2, where 10 indicates error - */ - - /* Adjust Second Byte range for special First Bytes(E0,ED,F0,F4) */ - /* Overlaps lead to index 9~15, which are illegal in range table */ - __m256i shift1, pos, range2; - /* shift1 = (input, prev_input) << 1 byte */ - shift1 = push_last_byte_of_a_to_b (prev_input, input); - pos = _mm256_sub_epi8 (shift1, _mm256_set1_epi8 (0xEF)); - /* - * shift1: | EF F0 ... FE | FF 00 ... ... DE | DF E0 ... EE | - * pos: | 0 1 15 | 16 17 239| 240 241 255| - * pos-240: | 0 0 0 | 0 0 0 | 0 1 15 | - * pos+112: | 112 113 127| >= 128 | >= 128 | - */ - tmp1 = _mm256_subs_epu8 (pos, _mm256_set1_epi8 ((char)240)); - range2 = _mm256_shuffle_epi8 (df_ee_tbl, tmp1); - tmp2 = _mm256_adds_epu8 (pos, _mm256_set1_epi8 (112)); - range2 = _mm256_add_epi8 (range2, _mm256_shuffle_epi8 (ef_fe_tbl, tmp2)); - - range = _mm256_add_epi8 (range, range2); - - /* Load min and max values per calculated range index */ - __m256i minv = _mm256_shuffle_epi8 (range_min_tbl, range); - __m256i maxv = _mm256_shuffle_epi8 (range_max_tbl, range); - - /* Check value range */ - error = _mm256_cmpgt_epi8(minv, input); - error = _mm256_or_si256(error, _mm256_cmpgt_epi8(input, maxv)); - /* 5% performance drop from this conditional branch */ - if (!_mm256_testz_si256(error, error)) { - break; - } - - prev_input = input; - prev_first_len = first_len; - - data += 32; - len -= 32; - err_pos += 32; - } - - /* Error in first 16 bytes */ - if (err_pos == 1) { - goto do_naive; - } - - /* Find previous token (not 80~BF) */ - int32_t token4 = _mm256_extract_epi32 (prev_input, 7); - const int8_t *token = (const int8_t *) &token4; - int lookahead = 0; - - if (token[3] > (int8_t) 0xBF) { - lookahead = 1; - } - else if (token[2] > (int8_t) 0xBF) { - lookahead = 2; - } - else if (token[1] > (int8_t) 0xBF) { - lookahead = 3; - } - - data -= lookahead; - len += lookahead; - err_pos -= lookahead; - } - - /* Check remaining bytes with naive method */ -do_naive: - if (len > 0) { - off_t err_pos2 = rspamd_fast_utf8_validate_ref (data, len); - - if (err_pos2) { - return err_pos + err_pos2 - 1; - } - } - - return 0; -} - -#ifndef __clang__ -#pragma GCC pop_options -#endif - diff --git a/contrib/fastutf8/fastutf8.c b/contrib/fastutf8/fastutf8.c deleted file mode 100644 index 89becaf0a..000000000 --- a/contrib/fastutf8/fastutf8.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Yibo Cai - * Copyright (c) 2019 Vsevolod Stakhov - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "fastutf8.h" -#include "libcryptobox/platform_config.h" - - -/* - * http://www.unicode.org/versions/Unicode6.0.0/ch03.pdf - page 94 - * - * Table 3-7. Well-Formed UTF-8 Byte Sequences - * - * +--------------------+------------+-------------+------------+-------------+ - * | Code Points | First Byte | Second Byte | Third Byte | Fourth Byte | - * +--------------------+------------+-------------+------------+-------------+ - * | U+0000..U+007F | 00..7F | | | | - * +--------------------+------------+-------------+------------+-------------+ - * | U+0080..U+07FF | C2..DF | 80..BF | | | - * +--------------------+------------+-------------+------------+-------------+ - * | U+0800..U+0FFF | E0 | A0..BF | 80..BF | | - * +--------------------+------------+-------------+------------+-------------+ - * | U+1000..U+CFFF | E1..EC | 80..BF | 80..BF | | - * +--------------------+------------+-------------+------------+-------------+ - * | U+D000..U+D7FF | ED | 80..9F | 80..BF | | - * +--------------------+------------+-------------+------------+-------------+ - * | U+E000..U+FFFF | EE..EF | 80..BF | 80..BF | | - * +--------------------+------------+-------------+------------+-------------+ - * | U+10000..U+3FFFF | F0 | 90..BF | 80..BF | 80..BF | - * +--------------------+------------+-------------+------------+-------------+ - * | U+40000..U+FFFFF | F1..F3 | 80..BF | 80..BF | 80..BF | - * +--------------------+------------+-------------+------------+-------------+ - * | U+100000..U+10FFFF | F4 | 80..8F | 80..BF | 80..BF | - * +--------------------+------------+-------------+------------+-------------+ - */ - -/* Return 0 - success, >0 - index (1 based) of first error char */ -off_t -rspamd_fast_utf8_validate_ref (const unsigned char *data, size_t len) -{ - off_t err_pos = 1; - - while (len) { - int bytes; - const unsigned char byte1 = data[0]; - - /* 00..7F */ - if (byte1 <= 0x7F) { - bytes = 1; - /* C2..DF, 80..BF */ - } - else if (len >= 2 && byte1 >= 0xC2 && byte1 <= 0xDF && - (signed char) data[1] <= (signed char) 0xBF) { - bytes = 2; - } - else if (len >= 3) { - const unsigned char byte2 = data[1]; - - /* Is byte2, byte3 between 0x80 ~ 0xBF */ - const int byte2_ok = (signed char) byte2 <= (signed char) 0xBF; - const int byte3_ok = (signed char) data[2] <= (signed char) 0xBF; - - if (byte2_ok && byte3_ok && - /* E0, A0..BF, 80..BF */ - ((byte1 == 0xE0 && byte2 >= 0xA0) || - /* E1..EC, 80..BF, 80..BF */ - (byte1 >= 0xE1 && byte1 <= 0xEC) || - /* ED, 80..9F, 80..BF */ - (byte1 == 0xED && byte2 <= 0x9F) || - /* EE..EF, 80..BF, 80..BF */ - (byte1 >= 0xEE && byte1 <= 0xEF))) { - bytes = 3; - } - else if (len >= 4) { - /* Is byte4 between 0x80 ~ 0xBF */ - const int byte4_ok = (signed char) data[3] <= (signed char) 0xBF; - - if (byte2_ok && byte3_ok && byte4_ok && - /* F0, 90..BF, 80..BF, 80..BF */ - ((byte1 == 0xF0 && byte2 >= 0x90) || - /* F1..F3, 80..BF, 80..BF, 80..BF */ - (byte1 >= 0xF1 && byte1 <= 0xF3) || - /* F4, 80..8F, 80..BF, 80..BF */ - (byte1 == 0xF4 && byte2 <= 0x8F))) { - bytes = 4; - } - else { - return err_pos; - } - } - else { - return err_pos; - } - } - else { - return err_pos; - } - - len -= bytes; - err_pos += bytes; - data += bytes; - } - - return 0; -} - -/* Prototypes */ -#if defined(HAVE_SSE41) && defined(__x86_64__) -extern off_t rspamd_fast_utf8_validate_sse41 (const unsigned char *data, size_t len); -#endif -#if defined(HAVE_AVX2) && defined(__x86_64__) -extern off_t rspamd_fast_utf8_validate_avx2 (const unsigned char *data, size_t len); -#endif - -static off_t (*validate_func) (const unsigned char *data, size_t len) = - rspamd_fast_utf8_validate_ref; - - -void -rspamd_fast_utf8_library_init (unsigned flags) -{ -#if defined(HAVE_SSE41) && defined(__x86_64__) - if (flags & RSPAMD_FAST_UTF8_FLAG_SSE41) { - validate_func = rspamd_fast_utf8_validate_sse41; - } -#endif -#if defined(HAVE_AVX2) && defined(__x86_64__) - if (flags & RSPAMD_FAST_UTF8_FLAG_AVX2) { - validate_func = rspamd_fast_utf8_validate_avx2; - } -#endif -} - -off_t -rspamd_fast_utf8_validate (const unsigned char *data, size_t len) -{ - return len >= 64 ? - validate_func (data, len) : - rspamd_fast_utf8_validate_ref (data, len); -} \ No newline at end of file diff --git a/contrib/fastutf8/fastutf8.h b/contrib/fastutf8/fastutf8.h deleted file mode 100644 index a1e9cbf03..000000000 --- a/contrib/fastutf8/fastutf8.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Yibo Cai - * Copyright (c) 2019 Vsevolod Stakhov - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef RSPAMD_FASTUTF8_H -#define RSPAMD_FASTUTF8_H - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif -enum rspamd_fast_utf8_cpu_flags { - RSPAMD_FAST_UTF8_FLAG_SSE41 = 1u << 0u, - RSPAMD_FAST_UTF8_FLAG_AVX2 = 1u << 1u, -}; - -/** - * Called to init codecs - * @param flags - */ -void rspamd_fast_utf8_library_init(unsigned flags); - -/** - * Called to validate input using fast codec - * @param data - * @param len - * @return - */ -off_t rspamd_fast_utf8_validate(const unsigned char *data, size_t len); - -/** - * Use plain C implementation - * @param data - * @param len - * @return - */ -off_t rspamd_fast_utf8_validate_ref(const unsigned char *data, size_t len); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/contrib/fastutf8/sse41.c b/contrib/fastutf8/sse41.c deleted file mode 100644 index df338cf27..000000000 --- a/contrib/fastutf8/sse41.c +++ /dev/null @@ -1,272 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Yibo Cai - * Copyright (c) 2019 Vsevolod Stakhov - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "config.h" -#include "fastutf8.h" -#include "platform_config.h" - -#ifndef __clang__ -#pragma GCC push_options -#pragma GCC target("sse4.1") -#endif - -#ifndef __SSE2__ -#define __SSE2__ -#endif -#ifndef __SSE__ -#define __SSE__ -#endif -#ifndef __SSEE3__ -#define __SSEE3__ -#endif -#ifndef __SSE4_1__ -#define __SSE4_1__ -#endif - -#include - -/* - * Map high nibble of "First Byte" to legal character length minus 1 - * 0x00 ~ 0xBF --> 0 - * 0xC0 ~ 0xDF --> 1 - * 0xE0 ~ 0xEF --> 2 - * 0xF0 ~ 0xFF --> 3 - */ -static const int8_t _first_len_tbl[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, -}; - -/* Map "First Byte" to 8-th item of range table (0xC2 ~ 0xF4) */ -static const int8_t _first_range_tbl[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, -}; - -/* - * Range table, map range index to min and max values - * Index 0 : 00 ~ 7F (First Byte, ascii) - * Index 1,2,3: 80 ~ BF (Second, Third, Fourth Byte) - * Index 4 : A0 ~ BF (Second Byte after E0) - * Index 5 : 80 ~ 9F (Second Byte after ED) - * Index 6 : 90 ~ BF (Second Byte after F0) - * Index 7 : 80 ~ 8F (Second Byte after F4) - * Index 8 : C2 ~ F4 (First Byte, non ascii) - * Index 9~15 : illegal: i >= 127 && i <= -128 - */ -static const int8_t _range_min_tbl[] = { - 0x00, 0x80, 0x80, 0x80, 0xA0, 0x80, 0x90, 0x80, - 0xC2, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, -}; -static const int8_t _range_max_tbl[] = { - 0x7F, 0xBF, 0xBF, 0xBF, 0xBF, 0x9F, 0xBF, 0x8F, - 0xF4, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -}; - -/* - * Tables for fast handling of four special First Bytes(E0,ED,F0,F4), after - * which the Second Byte are not 80~BF. It contains "range index adjustment". - * +------------+---------------+------------------+----------------+ - * | First Byte | original range| range adjustment | adjusted range | - * +------------+---------------+------------------+----------------+ - * | E0 | 2 | 2 | 4 | - * +------------+---------------+------------------+----------------+ - * | ED | 2 | 3 | 5 | - * +------------+---------------+------------------+----------------+ - * | F0 | 3 | 3 | 6 | - * +------------+---------------+------------------+----------------+ - * | F4 | 4 | 4 | 8 | - * +------------+---------------+------------------+----------------+ - */ -/* index1 -> E0, index14 -> ED */ -static const int8_t _df_ee_tbl[] = { - 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, -}; -/* index1 -> F0, index5 -> F4 */ -static const int8_t _ef_fe_tbl[] = { - 0, 3, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -off_t -rspamd_fast_utf8_validate_sse41 (const unsigned char *data, size_t len) - __attribute__((__target__("sse4.1"))); - -/* Return 0 - success, >0 - first error char(if RET_ERR_IDX = 1) */ -off_t -rspamd_fast_utf8_validate_sse41 (const unsigned char *data, size_t len) -{ - off_t err_pos = 1; - - if (len >= 16) { - __m128i prev_input = _mm_set1_epi8 (0); - __m128i prev_first_len = _mm_set1_epi8 (0); - - /* Cached tables */ - const __m128i first_len_tbl = - _mm_lddqu_si128 ((const __m128i *) _first_len_tbl); - const __m128i first_range_tbl = - _mm_lddqu_si128 ((const __m128i *) _first_range_tbl); - const __m128i range_min_tbl = - _mm_lddqu_si128 ((const __m128i *) _range_min_tbl); - const __m128i range_max_tbl = - _mm_lddqu_si128 ((const __m128i *) _range_max_tbl); - const __m128i df_ee_tbl = - _mm_lddqu_si128 ((const __m128i *) _df_ee_tbl); - const __m128i ef_fe_tbl = - _mm_lddqu_si128 ((const __m128i *) _ef_fe_tbl); - - __m128i error = _mm_set1_epi8 (0); - - while (len >= 16) { - const __m128i input = _mm_lddqu_si128 ((const __m128i *) data); - - /* high_nibbles = input >> 4 */ - const __m128i high_nibbles = - _mm_and_si128 (_mm_srli_epi16 (input, 4), _mm_set1_epi8 (0x0F)); - - /* first_len = legal character length minus 1 */ - /* 0 for 00~7F, 1 for C0~DF, 2 for E0~EF, 3 for F0~FF */ - /* first_len = first_len_tbl[high_nibbles] */ - __m128i first_len = _mm_shuffle_epi8 (first_len_tbl, high_nibbles); - - /* First Byte: set range index to 8 for bytes within 0xC0 ~ 0xFF */ - /* range = first_range_tbl[high_nibbles] */ - __m128i range = _mm_shuffle_epi8 (first_range_tbl, high_nibbles); - - /* Second Byte: set range index to first_len */ - /* 0 for 00~7F, 1 for C0~DF, 2 for E0~EF, 3 for F0~FF */ - /* range |= (first_len, prev_first_len) << 1 byte */ - range = _mm_or_si128 ( - range, _mm_alignr_epi8(first_len, prev_first_len, 15)); - - /* Third Byte: set range index to saturate_sub(first_len, 1) */ - /* 0 for 00~7F, 0 for C0~DF, 1 for E0~EF, 2 for F0~FF */ - __m128i tmp1, tmp2; - /* tmp1 = saturate_sub(first_len, 1) */ - tmp1 = _mm_subs_epu8 (first_len, _mm_set1_epi8 (1)); - /* tmp2 = saturate_sub(prev_first_len, 1) */ - tmp2 = _mm_subs_epu8 (prev_first_len, _mm_set1_epi8 (1)); - /* range |= (tmp1, tmp2) << 2 bytes */ - range = _mm_or_si128 (range, _mm_alignr_epi8(tmp1, tmp2, 14)); - - /* Fourth Byte: set range index to saturate_sub(first_len, 2) */ - /* 0 for 00~7F, 0 for C0~DF, 0 for E0~EF, 1 for F0~FF */ - /* tmp1 = saturate_sub(first_len, 2) */ - tmp1 = _mm_subs_epu8 (first_len, _mm_set1_epi8 (2)); - /* tmp2 = saturate_sub(prev_first_len, 2) */ - tmp2 = _mm_subs_epu8 (prev_first_len, _mm_set1_epi8 (2)); - /* range |= (tmp1, tmp2) << 3 bytes */ - range = _mm_or_si128 (range, _mm_alignr_epi8(tmp1, tmp2, 13)); - - /* - * Now we have below range indices caluclated - * Correct cases: - * - 8 for C0~FF - * - 3 for 1st byte after F0~FF - * - 2 for 1st byte after E0~EF or 2nd byte after F0~FF - * - 1 for 1st byte after C0~DF or 2nd byte after E0~EF or - * 3rd byte after F0~FF - * - 0 for others - * Error cases: - * 9,10,11 if non ascii First Byte overlaps - * E.g., F1 80 C2 90 --> 8 3 10 2, where 10 indicates error - */ - - /* Adjust Second Byte range for special First Bytes(E0,ED,F0,F4) */ - /* Overlaps lead to index 9~15, which are illegal in range table */ - __m128i shift1, pos, range2; - /* shift1 = (input, prev_input) << 1 byte */ - shift1 = _mm_alignr_epi8(input, prev_input, 15); - pos = _mm_sub_epi8 (shift1, _mm_set1_epi8 (0xEF)); - /* - * shift1: | EF F0 ... FE | FF 00 ... ... DE | DF E0 ... EE | - * pos: | 0 1 15 | 16 17 239| 240 241 255| - * pos-240: | 0 0 0 | 0 0 0 | 0 1 15 | - * pos+112: | 112 113 127| >= 128 | >= 128 | - */ - tmp1 = _mm_subs_epu8 (pos, _mm_set1_epi8 ((char)240)); - range2 = _mm_shuffle_epi8 (df_ee_tbl, tmp1); - tmp2 = _mm_adds_epu8 (pos, _mm_set1_epi8 (112)); - range2 = _mm_add_epi8 (range2, _mm_shuffle_epi8 (ef_fe_tbl, tmp2)); - - range = _mm_add_epi8 (range, range2); - - /* Load min and max values per calculated range index */ - __m128i minv = _mm_shuffle_epi8 (range_min_tbl, range); - __m128i maxv = _mm_shuffle_epi8 (range_max_tbl, range); - - /* Check value range */ - error = _mm_cmplt_epi8(input, minv); - error = _mm_or_si128(error, _mm_cmpgt_epi8(input, maxv)); - /* 5% performance drop from this conditional branch */ - if (!_mm_testz_si128(error, error)) { - break; - } - - prev_input = input; - prev_first_len = first_len; - - data += 16; - len -= 16; - err_pos += 16; - } - - /* Error in first 16 bytes */ - if (err_pos == 1) { - goto do_naive; - } - - /* Find previous token (not 80~BF) */ - int32_t token4 = _mm_extract_epi32 (prev_input, 3); - const int8_t *token = (const int8_t *) &token4; - int lookahead = 0; - - if (token[3] > (int8_t) 0xBF) { - lookahead = 1; - } - else if (token[2] > (int8_t) 0xBF) { - lookahead = 2; - } - else if (token[1] > (int8_t) 0xBF) { - lookahead = 3; - } - - data -= lookahead; - len += lookahead; - err_pos -= lookahead; - } - - do_naive: - if (len > 0) { - off_t err_pos2 = rspamd_fast_utf8_validate_ref (data, len); - - if (err_pos2) { - return err_pos + err_pos2 - 1; - } - } - - return 0; -} - -#ifndef __clang__ -#pragma GCC pop_options -#endif \ No newline at end of file diff --git a/contrib/simdutf/CMakeLists.txt b/contrib/simdutf/CMakeLists.txt new file mode 100644 index 000000000..f07a100d0 --- /dev/null +++ b/contrib/simdutf/CMakeLists.txt @@ -0,0 +1,114 @@ +cmake_minimum_required(VERSION 3.15) + +project(simdutf + DESCRIPTION "Fast Unicode validation, transcoding and processing" + LANGUAGES CXX + VERSION 5.6.3 +) + +include (TestBigEndian) +TEST_BIG_ENDIAN(IS_BIG_ENDIAN) +if(IS_BIG_ENDIAN) + message(STATUS "Big-endian system detected.") +endif() + +include(GNUInstallDirs) +# The following requires CMake 3.21. +# if(PROJECT_IS_TOP_LEVEL) +# message(STATUS "Building simdutf as a top-level project.") +# include(CTest) +#else() +# message(STATUS "Building simdutf as a subproject.") +#endif(PROJECT_IS_TOP_LEVEL) +include(CTest) +include(cmake/simdutf-flags.cmake) + +set(SIMDUTF_LIB_VERSION "11.0.0" CACHE STRING "simdutf library version") +set(SIMDUTF_LIB_SOVERSION "11" CACHE STRING "simdutf library soversion") +option(SIMDUTF_TESTS "Whether the tests are included as part of the CMake Build." OFF) +option(SIMDUTF_BENCHMARKS "Whether the benchmarks are included as part of the CMake Build." OFF) +option(SIMDUTF_TOOLS "Whether the tools are included as part of the CMake build. Requires C++17 or better." OFF) +option(SIMDUTF_FUZZERS "Whether to build the fuzzers." OFF) + + +set(SIMDUTF_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + +add_subdirectory(src) + +message(STATUS "Compiling using the C++ standard:" ${CMAKE_CXX_STANDARD}) +# ---- Install rules ---- +add_library(rspamd-simdutf ALIAS simdutf) + +set_target_properties( + simdutf PROPERTIES + VERSION "${SIMDUTF_LIB_VERSION}" + SOVERSION "${SIMDUTF_LIB_SOVERSION}" + WINDOWS_EXPORT_ALL_SYMBOLS YES +) + +include(CMakePackageConfigHelpers) +include(GNUInstallDirs) + +configure_file(cmake/simdutf-config.cmake.in simdutf-config.cmake @ONLY) + +write_basic_package_version_file( + simdutf-config-version.cmake + COMPATIBILITY SameMinorVersion +) + +set( + SIMDUTF_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/simdutf" + CACHE STRING "CMake package config location relative to the install prefix" +) +mark_as_advanced(SIMDUTF_INSTALL_CMAKEDIR) + + +# pkg-config +include(cmake/JoinPaths.cmake) +join_paths(PKGCONFIG_INCLUDEDIR "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}") +join_paths(PKGCONFIG_LIBDIR "\${prefix}" "${CMAKE_INSTALL_LIBDIR}") + +if(NOT SIMDUTF_SANITIZE) + find_program(GREP grep) + find_program(NM nm) + if((NOT GREP) OR (NOT NM)) + message("grep and nm are unavailable on this system.") + else() + add_test( + NAME "avoid_abort" + # Under FreeBSD, the __cxa_guard_abort symbol may appear but it is fine. + # So we want to look for abort as a test. + COMMAND sh -c "${NM} $ | ${GREP} ' _*abort' || exit 0 && exit 1" + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + ) + add_test( + NAME "avoid_cout" + COMMAND sh -c "${NM} $ | ${GREP} ' _*cout' || exit 0 && exit 1" + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + ) + add_test( + NAME "avoid_cerr" + COMMAND sh -c "${NM} $ | ${GREP} ' _*cerr' || exit 0 && exit 1" + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + ) + add_test( + NAME "avoid_printf" + COMMAND sh -c "${NM} $ | ${GREP} ' _*printf' || exit 0 && exit 1" + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + ) + add_test( + NAME "avoid_stdout" + COMMAND sh -c "${NM} $ | ${GREP} stdout || exit 0 && exit 1" + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + ) + add_test( + NAME "avoid_stderr" + COMMAND sh -c "${NM} $ | ${GREP} stderr || exit 0 && exit 1" + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + ) + endif() +endif() + +if(SIMDUTF_FUZZERS) + add_subdirectory(fuzz) +endif() diff --git a/contrib/simdutf/LICENSE-APACHE b/contrib/simdutf/LICENSE-APACHE new file mode 100644 index 000000000..fd2496567 --- /dev/null +++ b/contrib/simdutf/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2020 The simdutf authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/contrib/simdutf/cmake/CPM.cmake b/contrib/simdutf/cmake/CPM.cmake new file mode 100644 index 000000000..c82a38653 --- /dev/null +++ b/contrib/simdutf/cmake/CPM.cmake @@ -0,0 +1,1161 @@ +# CPM.cmake - CMake's missing package manager +# =========================================== +# See https://github.com/cpm-cmake/CPM.cmake for usage and update instructions. +# +# MIT License +# ----------- +#[[ + Copyright (c) 2019-2023 Lars Melchior and contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +]] + +cmake_minimum_required(VERSION 3.14 FATAL_ERROR) + +# Initialize logging prefix +if(NOT CPM_INDENT) + set(CPM_INDENT + "CPM:" + CACHE INTERNAL "" + ) +endif() + +if(NOT COMMAND cpm_message) + function(cpm_message) + message(${ARGV}) + endfunction() +endif() + +set(CURRENT_CPM_VERSION 0.38.7) + +get_filename_component(CPM_CURRENT_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}" REALPATH) +if(CPM_DIRECTORY) + if(NOT CPM_DIRECTORY STREQUAL CPM_CURRENT_DIRECTORY) + if(CPM_VERSION VERSION_LESS CURRENT_CPM_VERSION) + message( + AUTHOR_WARNING + "${CPM_INDENT} \ +A dependency is using a more recent CPM version (${CURRENT_CPM_VERSION}) than the current project (${CPM_VERSION}). \ +It is recommended to upgrade CPM to the most recent version. \ +See https://github.com/cpm-cmake/CPM.cmake for more information." + ) + endif() + if(${CMAKE_VERSION} VERSION_LESS "3.17.0") + include(FetchContent) + endif() + return() + endif() + + get_property( + CPM_INITIALIZED GLOBAL "" + PROPERTY CPM_INITIALIZED + SET + ) + if(CPM_INITIALIZED) + return() + endif() +endif() + +if(CURRENT_CPM_VERSION MATCHES "development-version") + message( + WARNING "${CPM_INDENT} Your project is using an unstable development version of CPM.cmake. \ +Please update to a recent release if possible. \ +See https://github.com/cpm-cmake/CPM.cmake for details." + ) +endif() + +set_property(GLOBAL PROPERTY CPM_INITIALIZED true) + +macro(cpm_set_policies) + # the policy allows us to change options without caching + cmake_policy(SET CMP0077 NEW) + set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) + + # the policy allows us to change set(CACHE) without caching + if(POLICY CMP0126) + cmake_policy(SET CMP0126 NEW) + set(CMAKE_POLICY_DEFAULT_CMP0126 NEW) + endif() + + # The policy uses the download time for timestamp, instead of the timestamp in the archive. This + # allows for proper rebuilds when a projects url changes + if(POLICY CMP0135) + cmake_policy(SET CMP0135 NEW) + set(CMAKE_POLICY_DEFAULT_CMP0135 NEW) + endif() + + # treat relative git repository paths as being relative to the parent project's remote + if(POLICY CMP0150) + cmake_policy(SET CMP0150 NEW) + set(CMAKE_POLICY_DEFAULT_CMP0150 NEW) + endif() +endmacro() +cpm_set_policies() + +option(CPM_USE_LOCAL_PACKAGES "Always try to use `find_package` to get dependencies" + $ENV{CPM_USE_LOCAL_PACKAGES} +) +option(CPM_LOCAL_PACKAGES_ONLY "Only use `find_package` to get dependencies" + $ENV{CPM_LOCAL_PACKAGES_ONLY} +) +option(CPM_DOWNLOAD_ALL "Always download dependencies from source" $ENV{CPM_DOWNLOAD_ALL}) +option(CPM_DONT_UPDATE_MODULE_PATH "Don't update the module path to allow using find_package" + $ENV{CPM_DONT_UPDATE_MODULE_PATH} +) +option(CPM_DONT_CREATE_PACKAGE_LOCK "Don't create a package lock file in the binary path" + $ENV{CPM_DONT_CREATE_PACKAGE_LOCK} +) +option(CPM_INCLUDE_ALL_IN_PACKAGE_LOCK + "Add all packages added through CPM.cmake to the package lock" + $ENV{CPM_INCLUDE_ALL_IN_PACKAGE_LOCK} +) +option(CPM_USE_NAMED_CACHE_DIRECTORIES + "Use additional directory of package name in cache on the most nested level." + $ENV{CPM_USE_NAMED_CACHE_DIRECTORIES} +) + +set(CPM_VERSION + ${CURRENT_CPM_VERSION} + CACHE INTERNAL "" +) +set(CPM_DIRECTORY + ${CPM_CURRENT_DIRECTORY} + CACHE INTERNAL "" +) +set(CPM_FILE + ${CMAKE_CURRENT_LIST_FILE} + CACHE INTERNAL "" +) +set(CPM_PACKAGES + "" + CACHE INTERNAL "" +) +set(CPM_DRY_RUN + OFF + CACHE INTERNAL "Don't download or configure dependencies (for testing)" +) + +if(DEFINED ENV{CPM_SOURCE_CACHE}) + set(CPM_SOURCE_CACHE_DEFAULT $ENV{CPM_SOURCE_CACHE}) +else() + set(CPM_SOURCE_CACHE_DEFAULT OFF) +endif() + +set(CPM_SOURCE_CACHE + ${CPM_SOURCE_CACHE_DEFAULT} + CACHE PATH "Directory to download CPM dependencies" +) + +if(NOT CPM_DONT_UPDATE_MODULE_PATH) + set(CPM_MODULE_PATH + "${CMAKE_BINARY_DIR}/CPM_modules" + CACHE INTERNAL "" + ) + # remove old modules + file(REMOVE_RECURSE ${CPM_MODULE_PATH}) + file(MAKE_DIRECTORY ${CPM_MODULE_PATH}) + # locally added CPM modules should override global packages + set(CMAKE_MODULE_PATH "${CPM_MODULE_PATH};${CMAKE_MODULE_PATH}") +endif() + +if(NOT CPM_DONT_CREATE_PACKAGE_LOCK) + set(CPM_PACKAGE_LOCK_FILE + "${CMAKE_BINARY_DIR}/cpm-package-lock.cmake" + CACHE INTERNAL "" + ) + file(WRITE ${CPM_PACKAGE_LOCK_FILE} + "# CPM Package Lock\n# This file should be committed to version control\n\n" + ) +endif() + +include(FetchContent) + +# Try to infer package name from git repository uri (path or url) +function(cpm_package_name_from_git_uri URI RESULT) + if("${URI}" MATCHES "([^/:]+)/?.git/?$") + set(${RESULT} + ${CMAKE_MATCH_1} + PARENT_SCOPE + ) + else() + unset(${RESULT} PARENT_SCOPE) + endif() +endfunction() + +# Try to infer package name and version from a url +function(cpm_package_name_and_ver_from_url url outName outVer) + if(url MATCHES "[/\\?]([a-zA-Z0-9_\\.-]+)\\.(tar|tar\\.gz|tar\\.bz2|zip|ZIP)(\\?|/|$)") + # We matched an archive + set(filename "${CMAKE_MATCH_1}") + + if(filename MATCHES "([a-zA-Z0-9_\\.-]+)[_-]v?(([0-9]+\\.)*[0-9]+[a-zA-Z0-9]*)") + # We matched - (ie foo-1.2.3) + set(${outName} + "${CMAKE_MATCH_1}" + PARENT_SCOPE + ) + set(${outVer} + "${CMAKE_MATCH_2}" + PARENT_SCOPE + ) + elseif(filename MATCHES "(([0-9]+\\.)+[0-9]+[a-zA-Z0-9]*)") + # We couldn't find a name, but we found a version + # + # In many cases (which we don't handle here) the url would look something like + # `irrelevant/ACTUAL_PACKAGE_NAME/irrelevant/1.2.3.zip`. In such a case we can't possibly + # distinguish the package name from the irrelevant bits. Moreover if we try to match the + # package name from the filename, we'd get bogus at best. + unset(${outName} PARENT_SCOPE) + set(${outVer} + "${CMAKE_MATCH_1}" + PARENT_SCOPE + ) + else() + # Boldly assume that the file name is the package name. + # + # Yes, something like `irrelevant/ACTUAL_NAME/irrelevant/download.zip` will ruin our day, but + # such cases should be quite rare. No popular service does this... we think. + set(${outName} + "${filename}" + PARENT_SCOPE + ) + unset(${outVer} PARENT_SCOPE) + endif() + else() + # No ideas yet what to do with non-archives + unset(${outName} PARENT_SCOPE) + unset(${outVer} PARENT_SCOPE) + endif() +endfunction() + +function(cpm_find_package NAME VERSION) + string(REPLACE " " ";" EXTRA_ARGS "${ARGN}") + find_package(${NAME} ${VERSION} ${EXTRA_ARGS} QUIET) + if(${CPM_ARGS_NAME}_FOUND) + if(DEFINED ${CPM_ARGS_NAME}_VERSION) + set(VERSION ${${CPM_ARGS_NAME}_VERSION}) + endif() + cpm_message(STATUS "${CPM_INDENT} Using local package ${CPM_ARGS_NAME}@${VERSION}") + CPMRegisterPackage(${CPM_ARGS_NAME} "${VERSION}") + set(CPM_PACKAGE_FOUND + YES + PARENT_SCOPE + ) + else() + set(CPM_PACKAGE_FOUND + NO + PARENT_SCOPE + ) + endif() +endfunction() + +# Create a custom FindXXX.cmake module for a CPM package This prevents `find_package(NAME)` from +# finding the system library +function(cpm_create_module_file Name) + if(NOT CPM_DONT_UPDATE_MODULE_PATH) + # erase any previous modules + file(WRITE ${CPM_MODULE_PATH}/Find${Name}.cmake + "include(\"${CPM_FILE}\")\n${ARGN}\nset(${Name}_FOUND TRUE)" + ) + endif() +endfunction() + +# Find a package locally or fallback to CPMAddPackage +function(CPMFindPackage) + set(oneValueArgs NAME VERSION GIT_TAG FIND_PACKAGE_ARGUMENTS) + + cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "" ${ARGN}) + + if(NOT DEFINED CPM_ARGS_VERSION) + if(DEFINED CPM_ARGS_GIT_TAG) + cpm_get_version_from_git_tag("${CPM_ARGS_GIT_TAG}" CPM_ARGS_VERSION) + endif() + endif() + + set(downloadPackage ${CPM_DOWNLOAD_ALL}) + if(DEFINED CPM_DOWNLOAD_${CPM_ARGS_NAME}) + set(downloadPackage ${CPM_DOWNLOAD_${CPM_ARGS_NAME}}) + elseif(DEFINED ENV{CPM_DOWNLOAD_${CPM_ARGS_NAME}}) + set(downloadPackage $ENV{CPM_DOWNLOAD_${CPM_ARGS_NAME}}) + endif() + if(downloadPackage) + CPMAddPackage(${ARGN}) + cpm_export_variables(${CPM_ARGS_NAME}) + return() + endif() + + cpm_check_if_package_already_added(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}") + if(CPM_PACKAGE_ALREADY_ADDED) + cpm_export_variables(${CPM_ARGS_NAME}) + return() + endif() + + cpm_find_package(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}" ${CPM_ARGS_FIND_PACKAGE_ARGUMENTS}) + + if(NOT CPM_PACKAGE_FOUND) + CPMAddPackage(${ARGN}) + cpm_export_variables(${CPM_ARGS_NAME}) + endif() + +endfunction() + +# checks if a package has been added before +function(cpm_check_if_package_already_added CPM_ARGS_NAME CPM_ARGS_VERSION) + if("${CPM_ARGS_NAME}" IN_LIST CPM_PACKAGES) + CPMGetPackageVersion(${CPM_ARGS_NAME} CPM_PACKAGE_VERSION) + if("${CPM_PACKAGE_VERSION}" VERSION_LESS "${CPM_ARGS_VERSION}") + message( + WARNING + "${CPM_INDENT} Requires a newer version of ${CPM_ARGS_NAME} (${CPM_ARGS_VERSION}) than currently included (${CPM_PACKAGE_VERSION})." + ) + endif() + cpm_get_fetch_properties(${CPM_ARGS_NAME}) + set(${CPM_ARGS_NAME}_ADDED NO) + set(CPM_PACKAGE_ALREADY_ADDED + YES + PARENT_SCOPE + ) + cpm_export_variables(${CPM_ARGS_NAME}) + else() + set(CPM_PACKAGE_ALREADY_ADDED + NO + PARENT_SCOPE + ) + endif() +endfunction() + +# Parse the argument of CPMAddPackage in case a single one was provided and convert it to a list of +# arguments which can then be parsed idiomatically. For example gh:foo/bar@1.2.3 will be converted +# to: GITHUB_REPOSITORY;foo/bar;VERSION;1.2.3 +function(cpm_parse_add_package_single_arg arg outArgs) + # Look for a scheme + if("${arg}" MATCHES "^([a-zA-Z]+):(.+)$") + string(TOLOWER "${CMAKE_MATCH_1}" scheme) + set(uri "${CMAKE_MATCH_2}") + + # Check for CPM-specific schemes + if(scheme STREQUAL "gh") + set(out "GITHUB_REPOSITORY;${uri}") + set(packageType "git") + elseif(scheme STREQUAL "gl") + set(out "GITLAB_REPOSITORY;${uri}") + set(packageType "git") + elseif(scheme STREQUAL "bb") + set(out "BITBUCKET_REPOSITORY;${uri}") + set(packageType "git") + # A CPM-specific scheme was not found. Looks like this is a generic URL so try to determine + # type + elseif(arg MATCHES ".git/?(@|#|$)") + set(out "GIT_REPOSITORY;${arg}") + set(packageType "git") + else() + # Fall back to a URL + set(out "URL;${arg}") + set(packageType "archive") + + # We could also check for SVN since FetchContent supports it, but SVN is so rare these days. + # We just won't bother with the additional complexity it will induce in this function. SVN is + # done by multi-arg + endif() + else() + if(arg MATCHES ".git/?(@|#|$)") + set(out "GIT_REPOSITORY;${arg}") + set(packageType "git") + else() + # Give up + message(FATAL_ERROR "${CPM_INDENT} Can't determine package type of '${arg}'") + endif() + endif() + + # For all packages we interpret @... as version. Only replace the last occurrence. Thus URIs + # containing '@' can be used + string(REGEX REPLACE "@([^@]+)$" ";VERSION;\\1" out "${out}") + + # Parse the rest according to package type + if(packageType STREQUAL "git") + # For git repos we interpret #... as a tag or branch or commit hash + string(REGEX REPLACE "#([^#]+)$" ";GIT_TAG;\\1" out "${out}") + elseif(packageType STREQUAL "archive") + # For archives we interpret #... as a URL hash. + string(REGEX REPLACE "#([^#]+)$" ";URL_HASH;\\1" out "${out}") + # We don't try to parse the version if it's not provided explicitly. cpm_get_version_from_url + # should do this at a later point + else() + # We should never get here. This is an assertion and hitting it means there's a bug in the code + # above. A packageType was set, but not handled by this if-else. + message(FATAL_ERROR "${CPM_INDENT} Unsupported package type '${packageType}' of '${arg}'") + endif() + + set(${outArgs} + ${out} + PARENT_SCOPE + ) +endfunction() + +# Check that the working directory for a git repo is clean +function(cpm_check_git_working_dir_is_clean repoPath gitTag isClean) + + find_package(Git REQUIRED) + + if(NOT GIT_EXECUTABLE) + # No git executable, assume directory is clean + set(${isClean} + TRUE + PARENT_SCOPE + ) + return() + endif() + + # check for uncommitted changes + execute_process( + COMMAND ${GIT_EXECUTABLE} status --porcelain + RESULT_VARIABLE resultGitStatus + OUTPUT_VARIABLE repoStatus + OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET + WORKING_DIRECTORY ${repoPath} + ) + if(resultGitStatus) + # not supposed to happen, assume clean anyway + message(WARNING "${CPM_INDENT} Calling git status on folder ${repoPath} failed") + set(${isClean} + TRUE + PARENT_SCOPE + ) + return() + endif() + + if(NOT "${repoStatus}" STREQUAL "") + set(${isClean} + FALSE + PARENT_SCOPE + ) + return() + endif() + + # check for committed changes + execute_process( + COMMAND ${GIT_EXECUTABLE} diff -s --exit-code ${gitTag} + RESULT_VARIABLE resultGitDiff + OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_QUIET + WORKING_DIRECTORY ${repoPath} + ) + + if(${resultGitDiff} EQUAL 0) + set(${isClean} + TRUE + PARENT_SCOPE + ) + else() + set(${isClean} + FALSE + PARENT_SCOPE + ) + endif() + +endfunction() + +# method to overwrite internal FetchContent properties, to allow using CPM.cmake to overload +# FetchContent calls. As these are internal cmake properties, this method should be used carefully +# and may need modification in future CMake versions. Source: +# https://github.com/Kitware/CMake/blob/dc3d0b5a0a7d26d43d6cfeb511e224533b5d188f/Modules/FetchContent.cmake#L1152 +function(cpm_override_fetchcontent contentName) + cmake_parse_arguments(PARSE_ARGV 1 arg "" "SOURCE_DIR;BINARY_DIR" "") + if(NOT "${arg_UNPARSED_ARGUMENTS}" STREQUAL "") + message(FATAL_ERROR "${CPM_INDENT} Unsupported arguments: ${arg_UNPARSED_ARGUMENTS}") + endif() + + string(TOLOWER ${contentName} contentNameLower) + set(prefix "_FetchContent_${contentNameLower}") + + set(propertyName "${prefix}_sourceDir") + define_property( + GLOBAL + PROPERTY ${propertyName} + BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()" + FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}" + ) + set_property(GLOBAL PROPERTY ${propertyName} "${arg_SOURCE_DIR}") + + set(propertyName "${prefix}_binaryDir") + define_property( + GLOBAL + PROPERTY ${propertyName} + BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()" + FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}" + ) + set_property(GLOBAL PROPERTY ${propertyName} "${arg_BINARY_DIR}") + + set(propertyName "${prefix}_populated") + define_property( + GLOBAL + PROPERTY ${propertyName} + BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()" + FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}" + ) + set_property(GLOBAL PROPERTY ${propertyName} TRUE) +endfunction() + +# Download and add a package from source +function(CPMAddPackage) + cpm_set_policies() + + list(LENGTH ARGN argnLength) + if(argnLength EQUAL 1) + cpm_parse_add_package_single_arg("${ARGN}" ARGN) + + # The shorthand syntax implies EXCLUDE_FROM_ALL and SYSTEM + set(ARGN "${ARGN};EXCLUDE_FROM_ALL;YES;SYSTEM;YES;") + endif() + + set(oneValueArgs + NAME + FORCE + VERSION + GIT_TAG + DOWNLOAD_ONLY + GITHUB_REPOSITORY + GITLAB_REPOSITORY + BITBUCKET_REPOSITORY + GIT_REPOSITORY + SOURCE_DIR + FIND_PACKAGE_ARGUMENTS + NO_CACHE + SYSTEM + GIT_SHALLOW + EXCLUDE_FROM_ALL + SOURCE_SUBDIR + ) + + set(multiValueArgs URL OPTIONS DOWNLOAD_COMMAND) + + cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" "${ARGN}") + + # Set default values for arguments + + if(NOT DEFINED CPM_ARGS_VERSION) + if(DEFINED CPM_ARGS_GIT_TAG) + cpm_get_version_from_git_tag("${CPM_ARGS_GIT_TAG}" CPM_ARGS_VERSION) + endif() + endif() + + if(CPM_ARGS_DOWNLOAD_ONLY) + set(DOWNLOAD_ONLY ${CPM_ARGS_DOWNLOAD_ONLY}) + else() + set(DOWNLOAD_ONLY NO) + endif() + + if(DEFINED CPM_ARGS_GITHUB_REPOSITORY) + set(CPM_ARGS_GIT_REPOSITORY "https://github.com/${CPM_ARGS_GITHUB_REPOSITORY}.git") + elseif(DEFINED CPM_ARGS_GITLAB_REPOSITORY) + set(CPM_ARGS_GIT_REPOSITORY "https://gitlab.com/${CPM_ARGS_GITLAB_REPOSITORY}.git") + elseif(DEFINED CPM_ARGS_BITBUCKET_REPOSITORY) + set(CPM_ARGS_GIT_REPOSITORY "https://bitbucket.org/${CPM_ARGS_BITBUCKET_REPOSITORY}.git") + endif() + + if(DEFINED CPM_ARGS_GIT_REPOSITORY) + list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_REPOSITORY ${CPM_ARGS_GIT_REPOSITORY}) + if(NOT DEFINED CPM_ARGS_GIT_TAG) + set(CPM_ARGS_GIT_TAG v${CPM_ARGS_VERSION}) + endif() + + # If a name wasn't provided, try to infer it from the git repo + if(NOT DEFINED CPM_ARGS_NAME) + cpm_package_name_from_git_uri(${CPM_ARGS_GIT_REPOSITORY} CPM_ARGS_NAME) + endif() + endif() + + set(CPM_SKIP_FETCH FALSE) + + if(DEFINED CPM_ARGS_GIT_TAG) + list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_TAG ${CPM_ARGS_GIT_TAG}) + # If GIT_SHALLOW is explicitly specified, honor the value. + if(DEFINED CPM_ARGS_GIT_SHALLOW) + list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_SHALLOW ${CPM_ARGS_GIT_SHALLOW}) + endif() + endif() + + if(DEFINED CPM_ARGS_URL) + # If a name or version aren't provided, try to infer them from the URL + list(GET CPM_ARGS_URL 0 firstUrl) + cpm_package_name_and_ver_from_url(${firstUrl} nameFromUrl verFromUrl) + # If we fail to obtain name and version from the first URL, we could try other URLs if any. + # However multiple URLs are expected to be quite rare, so for now we won't bother. + + # If the caller provided their own name and version, they trump the inferred ones. + if(NOT DEFINED CPM_ARGS_NAME) + set(CPM_ARGS_NAME ${nameFromUrl}) + endif() + if(NOT DEFINED CPM_ARGS_VERSION) + set(CPM_ARGS_VERSION ${verFromUrl}) + endif() + + list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS URL "${CPM_ARGS_URL}") + endif() + + # Check for required arguments + + if(NOT DEFINED CPM_ARGS_NAME) + message( + FATAL_ERROR + "${CPM_INDENT} 'NAME' was not provided and couldn't be automatically inferred for package added with arguments: '${ARGN}'" + ) + endif() + + # Check if package has been added before + cpm_check_if_package_already_added(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}") + if(CPM_PACKAGE_ALREADY_ADDED) + cpm_export_variables(${CPM_ARGS_NAME}) + return() + endif() + + # Check for manual overrides + if(NOT CPM_ARGS_FORCE AND NOT "${CPM_${CPM_ARGS_NAME}_SOURCE}" STREQUAL "") + set(PACKAGE_SOURCE ${CPM_${CPM_ARGS_NAME}_SOURCE}) + set(CPM_${CPM_ARGS_NAME}_SOURCE "") + CPMAddPackage( + NAME "${CPM_ARGS_NAME}" + SOURCE_DIR "${PACKAGE_SOURCE}" + EXCLUDE_FROM_ALL "${CPM_ARGS_EXCLUDE_FROM_ALL}" + SYSTEM "${CPM_ARGS_SYSTEM}" + OPTIONS "${CPM_ARGS_OPTIONS}" + SOURCE_SUBDIR "${CPM_ARGS_SOURCE_SUBDIR}" + DOWNLOAD_ONLY "${DOWNLOAD_ONLY}" + FORCE True + ) + cpm_export_variables(${CPM_ARGS_NAME}) + return() + endif() + + # Check for available declaration + if(NOT CPM_ARGS_FORCE AND NOT "${CPM_DECLARATION_${CPM_ARGS_NAME}}" STREQUAL "") + set(declaration ${CPM_DECLARATION_${CPM_ARGS_NAME}}) + set(CPM_DECLARATION_${CPM_ARGS_NAME} "") + CPMAddPackage(${declaration}) + cpm_export_variables(${CPM_ARGS_NAME}) + # checking again to ensure version and option compatibility + cpm_check_if_package_already_added(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}") + return() + endif() + + if(NOT CPM_ARGS_FORCE) + if(CPM_USE_LOCAL_PACKAGES OR CPM_LOCAL_PACKAGES_ONLY) + cpm_find_package(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}" ${CPM_ARGS_FIND_PACKAGE_ARGUMENTS}) + + if(CPM_PACKAGE_FOUND) + cpm_export_variables(${CPM_ARGS_NAME}) + return() + endif() + + if(CPM_LOCAL_PACKAGES_ONLY) + message( + SEND_ERROR + "${CPM_INDENT} ${CPM_ARGS_NAME} not found via find_package(${CPM_ARGS_NAME} ${CPM_ARGS_VERSION})" + ) + endif() + endif() + endif() + + CPMRegisterPackage("${CPM_ARGS_NAME}" "${CPM_ARGS_VERSION}") + + if(DEFINED CPM_ARGS_GIT_TAG) + set(PACKAGE_INFO "${CPM_ARGS_GIT_TAG}") + elseif(DEFINED CPM_ARGS_SOURCE_DIR) + set(PACKAGE_INFO "${CPM_ARGS_SOURCE_DIR}") + else() + set(PACKAGE_INFO "${CPM_ARGS_VERSION}") + endif() + + if(DEFINED FETCHCONTENT_BASE_DIR) + # respect user's FETCHCONTENT_BASE_DIR if set + set(CPM_FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR}) + else() + set(CPM_FETCHCONTENT_BASE_DIR ${CMAKE_BINARY_DIR}/_deps) + endif() + + if(DEFINED CPM_ARGS_DOWNLOAD_COMMAND) + list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS DOWNLOAD_COMMAND ${CPM_ARGS_DOWNLOAD_COMMAND}) + elseif(DEFINED CPM_ARGS_SOURCE_DIR) + list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS SOURCE_DIR ${CPM_ARGS_SOURCE_DIR}) + if(NOT IS_ABSOLUTE ${CPM_ARGS_SOURCE_DIR}) + # Expand `CPM_ARGS_SOURCE_DIR` relative path. This is important because EXISTS doesn't work + # for relative paths. + get_filename_component( + source_directory ${CPM_ARGS_SOURCE_DIR} REALPATH BASE_DIR ${CMAKE_CURRENT_BINARY_DIR} + ) + else() + set(source_directory ${CPM_ARGS_SOURCE_DIR}) + endif() + if(NOT EXISTS ${source_directory}) + string(TOLOWER ${CPM_ARGS_NAME} lower_case_name) + # remove timestamps so CMake will re-download the dependency + file(REMOVE_RECURSE "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-subbuild") + endif() + elseif(CPM_SOURCE_CACHE AND NOT CPM_ARGS_NO_CACHE) + string(TOLOWER ${CPM_ARGS_NAME} lower_case_name) + set(origin_parameters ${CPM_ARGS_UNPARSED_ARGUMENTS}) + list(SORT origin_parameters) + if(CPM_USE_NAMED_CACHE_DIRECTORIES) + string(SHA1 origin_hash "${origin_parameters};NEW_CACHE_STRUCTURE_TAG") + set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${origin_hash}/${CPM_ARGS_NAME}) + else() + string(SHA1 origin_hash "${origin_parameters}") + set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${origin_hash}) + endif() + # Expand `download_directory` relative path. This is important because EXISTS doesn't work for + # relative paths. + get_filename_component(download_directory ${download_directory} ABSOLUTE) + list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS SOURCE_DIR ${download_directory}) + + if(CPM_SOURCE_CACHE) + file(LOCK ${download_directory}/../cmake.lock) + endif() + + if(EXISTS ${download_directory}) + if(CPM_SOURCE_CACHE) + file(LOCK ${download_directory}/../cmake.lock RELEASE) + endif() + + cpm_store_fetch_properties( + ${CPM_ARGS_NAME} "${download_directory}" + "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-build" + ) + cpm_get_fetch_properties("${CPM_ARGS_NAME}") + + if(DEFINED CPM_ARGS_GIT_TAG AND NOT (PATCH_COMMAND IN_LIST CPM_ARGS_UNPARSED_ARGUMENTS)) + # warn if cache has been changed since checkout + cpm_check_git_working_dir_is_clean(${download_directory} ${CPM_ARGS_GIT_TAG} IS_CLEAN) + if(NOT ${IS_CLEAN}) + message( + WARNING "${CPM_INDENT} Cache for ${CPM_ARGS_NAME} (${download_directory}) is dirty" + ) + endif() + endif() + + cpm_add_subdirectory( + "${CPM_ARGS_NAME}" + "${DOWNLOAD_ONLY}" + "${${CPM_ARGS_NAME}_SOURCE_DIR}/${CPM_ARGS_SOURCE_SUBDIR}" + "${${CPM_ARGS_NAME}_BINARY_DIR}" + "${CPM_ARGS_EXCLUDE_FROM_ALL}" + "${CPM_ARGS_SYSTEM}" + "${CPM_ARGS_OPTIONS}" + ) + set(PACKAGE_INFO "${PACKAGE_INFO} at ${download_directory}") + + # As the source dir is already cached/populated, we override the call to FetchContent. + set(CPM_SKIP_FETCH TRUE) + cpm_override_fetchcontent( + "${lower_case_name}" SOURCE_DIR "${${CPM_ARGS_NAME}_SOURCE_DIR}/${CPM_ARGS_SOURCE_SUBDIR}" + BINARY_DIR "${${CPM_ARGS_NAME}_BINARY_DIR}" + ) + + else() + # Enable shallow clone when GIT_TAG is not a commit hash. Our guess may not be accurate, but + # it should guarantee no commit hash get mis-detected. + if(NOT DEFINED CPM_ARGS_GIT_SHALLOW) + cpm_is_git_tag_commit_hash("${CPM_ARGS_GIT_TAG}" IS_HASH) + if(NOT ${IS_HASH}) + list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS GIT_SHALLOW TRUE) + endif() + endif() + + # remove timestamps so CMake will re-download the dependency + file(REMOVE_RECURSE ${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-subbuild) + set(PACKAGE_INFO "${PACKAGE_INFO} to ${download_directory}") + endif() + endif() + + cpm_create_module_file(${CPM_ARGS_NAME} "CPMAddPackage(\"${ARGN}\")") + + if(CPM_PACKAGE_LOCK_ENABLED) + if((CPM_ARGS_VERSION AND NOT CPM_ARGS_SOURCE_DIR) OR CPM_INCLUDE_ALL_IN_PACKAGE_LOCK) + cpm_add_to_package_lock(${CPM_ARGS_NAME} "${ARGN}") + elseif(CPM_ARGS_SOURCE_DIR) + cpm_add_comment_to_package_lock(${CPM_ARGS_NAME} "local directory") + else() + cpm_add_comment_to_package_lock(${CPM_ARGS_NAME} "${ARGN}") + endif() + endif() + + cpm_message( + STATUS "${CPM_INDENT} Adding package ${CPM_ARGS_NAME}@${CPM_ARGS_VERSION} (${PACKAGE_INFO})" + ) + + if(NOT CPM_SKIP_FETCH) + cpm_declare_fetch( + "${CPM_ARGS_NAME}" "${CPM_ARGS_VERSION}" "${PACKAGE_INFO}" "${CPM_ARGS_UNPARSED_ARGUMENTS}" + ) + cpm_fetch_package("${CPM_ARGS_NAME}" populated) + if(CPM_SOURCE_CACHE AND download_directory) + file(LOCK ${download_directory}/../cmake.lock RELEASE) + endif() + if(${populated}) + cpm_add_subdirectory( + "${CPM_ARGS_NAME}" + "${DOWNLOAD_ONLY}" + "${${CPM_ARGS_NAME}_SOURCE_DIR}/${CPM_ARGS_SOURCE_SUBDIR}" + "${${CPM_ARGS_NAME}_BINARY_DIR}" + "${CPM_ARGS_EXCLUDE_FROM_ALL}" + "${CPM_ARGS_SYSTEM}" + "${CPM_ARGS_OPTIONS}" + ) + endif() + cpm_get_fetch_properties("${CPM_ARGS_NAME}") + endif() + + set(${CPM_ARGS_NAME}_ADDED YES) + cpm_export_variables("${CPM_ARGS_NAME}") +endfunction() + +# Fetch a previously declared package +macro(CPMGetPackage Name) + if(DEFINED "CPM_DECLARATION_${Name}") + CPMAddPackage(NAME ${Name}) + else() + message(SEND_ERROR "${CPM_INDENT} Cannot retrieve package ${Name}: no declaration available") + endif() +endmacro() + +# export variables available to the caller to the parent scope expects ${CPM_ARGS_NAME} to be set +macro(cpm_export_variables name) + set(${name}_SOURCE_DIR + "${${name}_SOURCE_DIR}" + PARENT_SCOPE + ) + set(${name}_BINARY_DIR + "${${name}_BINARY_DIR}" + PARENT_SCOPE + ) + set(${name}_ADDED + "${${name}_ADDED}" + PARENT_SCOPE + ) + set(CPM_LAST_PACKAGE_NAME + "${name}" + PARENT_SCOPE + ) +endmacro() + +# declares a package, so that any call to CPMAddPackage for the package name will use these +# arguments instead. Previous declarations will not be overridden. +macro(CPMDeclarePackage Name) + if(NOT DEFINED "CPM_DECLARATION_${Name}") + set("CPM_DECLARATION_${Name}" "${ARGN}") + endif() +endmacro() + +function(cpm_add_to_package_lock Name) + if(NOT CPM_DONT_CREATE_PACKAGE_LOCK) + cpm_prettify_package_arguments(PRETTY_ARGN false ${ARGN}) + file(APPEND ${CPM_PACKAGE_LOCK_FILE} "# ${Name}\nCPMDeclarePackage(${Name}\n${PRETTY_ARGN})\n") + endif() +endfunction() + +function(cpm_add_comment_to_package_lock Name) + if(NOT CPM_DONT_CREATE_PACKAGE_LOCK) + cpm_prettify_package_arguments(PRETTY_ARGN true ${ARGN}) + file(APPEND ${CPM_PACKAGE_LOCK_FILE} + "# ${Name} (unversioned)\n# CPMDeclarePackage(${Name}\n${PRETTY_ARGN}#)\n" + ) + endif() +endfunction() + +# includes the package lock file if it exists and creates a target `cpm-update-package-lock` to +# update it +macro(CPMUsePackageLock file) + if(NOT CPM_DONT_CREATE_PACKAGE_LOCK) + get_filename_component(CPM_ABSOLUTE_PACKAGE_LOCK_PATH ${file} ABSOLUTE) + if(EXISTS ${CPM_ABSOLUTE_PACKAGE_LOCK_PATH}) + include(${CPM_ABSOLUTE_PACKAGE_LOCK_PATH}) + endif() + if(NOT TARGET cpm-update-package-lock) + add_custom_target( + cpm-update-package-lock COMMAND ${CMAKE_COMMAND} -E copy ${CPM_PACKAGE_LOCK_FILE} + ${CPM_ABSOLUTE_PACKAGE_LOCK_PATH} + ) + endif() + set(CPM_PACKAGE_LOCK_ENABLED true) + endif() +endmacro() + +# registers a package that has been added to CPM +function(CPMRegisterPackage PACKAGE VERSION) + list(APPEND CPM_PACKAGES ${PACKAGE}) + set(CPM_PACKAGES + ${CPM_PACKAGES} + CACHE INTERNAL "" + ) + set("CPM_PACKAGE_${PACKAGE}_VERSION" + ${VERSION} + CACHE INTERNAL "" + ) +endfunction() + +# retrieve the current version of the package to ${OUTPUT} +function(CPMGetPackageVersion PACKAGE OUTPUT) + set(${OUTPUT} + "${CPM_PACKAGE_${PACKAGE}_VERSION}" + PARENT_SCOPE + ) +endfunction() + +# declares a package in FetchContent_Declare +function(cpm_declare_fetch PACKAGE VERSION INFO) + if(${CPM_DRY_RUN}) + cpm_message(STATUS "${CPM_INDENT} Package not declared (dry run)") + return() + endif() + + FetchContent_Declare(${PACKAGE} ${ARGN}) +endfunction() + +# returns properties for a package previously defined by cpm_declare_fetch +function(cpm_get_fetch_properties PACKAGE) + if(${CPM_DRY_RUN}) + return() + endif() + + set(${PACKAGE}_SOURCE_DIR + "${CPM_PACKAGE_${PACKAGE}_SOURCE_DIR}" + PARENT_SCOPE + ) + set(${PACKAGE}_BINARY_DIR + "${CPM_PACKAGE_${PACKAGE}_BINARY_DIR}" + PARENT_SCOPE + ) +endfunction() + +function(cpm_store_fetch_properties PACKAGE source_dir binary_dir) + if(${CPM_DRY_RUN}) + return() + endif() + + set(CPM_PACKAGE_${PACKAGE}_SOURCE_DIR + "${source_dir}" + CACHE INTERNAL "" + ) + set(CPM_PACKAGE_${PACKAGE}_BINARY_DIR + "${binary_dir}" + CACHE INTERNAL "" + ) +endfunction() + +# adds a package as a subdirectory if viable, according to provided options +function( + cpm_add_subdirectory + PACKAGE + DOWNLOAD_ONLY + SOURCE_DIR + BINARY_DIR + EXCLUDE + SYSTEM + OPTIONS +) + + if(NOT DOWNLOAD_ONLY AND EXISTS ${SOURCE_DIR}/CMakeLists.txt) + set(addSubdirectoryExtraArgs "") + if(EXCLUDE) + list(APPEND addSubdirectoryExtraArgs EXCLUDE_FROM_ALL) + endif() + if("${SYSTEM}" AND "${CMAKE_VERSION}" VERSION_GREATER_EQUAL "3.25") + # https://cmake.org/cmake/help/latest/prop_dir/SYSTEM.html#prop_dir:SYSTEM + list(APPEND addSubdirectoryExtraArgs SYSTEM) + endif() + if(OPTIONS) + foreach(OPTION ${OPTIONS}) + cpm_parse_option("${OPTION}") + set(${OPTION_KEY} "${OPTION_VALUE}") + endforeach() + endif() + set(CPM_OLD_INDENT "${CPM_INDENT}") + set(CPM_INDENT "${CPM_INDENT} ${PACKAGE}:") + add_subdirectory(${SOURCE_DIR} ${BINARY_DIR} ${addSubdirectoryExtraArgs}) + set(CPM_INDENT "${CPM_OLD_INDENT}") + endif() +endfunction() + +# downloads a previously declared package via FetchContent and exports the variables +# `${PACKAGE}_SOURCE_DIR` and `${PACKAGE}_BINARY_DIR` to the parent scope +function(cpm_fetch_package PACKAGE populated) + set(${populated} + FALSE + PARENT_SCOPE + ) + if(${CPM_DRY_RUN}) + cpm_message(STATUS "${CPM_INDENT} Package ${PACKAGE} not fetched (dry run)") + return() + endif() + + FetchContent_GetProperties(${PACKAGE}) + + string(TOLOWER "${PACKAGE}" lower_case_name) + + if(NOT ${lower_case_name}_POPULATED) + FetchContent_Populate(${PACKAGE}) + set(${populated} + TRUE + PARENT_SCOPE + ) + endif() + + cpm_store_fetch_properties( + ${CPM_ARGS_NAME} ${${lower_case_name}_SOURCE_DIR} ${${lower_case_name}_BINARY_DIR} + ) + + set(${PACKAGE}_SOURCE_DIR + ${${lower_case_name}_SOURCE_DIR} + PARENT_SCOPE + ) + set(${PACKAGE}_BINARY_DIR + ${${lower_case_name}_BINARY_DIR} + PARENT_SCOPE + ) +endfunction() + +# splits a package option +function(cpm_parse_option OPTION) + string(REGEX MATCH "^[^ ]+" OPTION_KEY "${OPTION}") + string(LENGTH "${OPTION}" OPTION_LENGTH) + string(LENGTH "${OPTION_KEY}" OPTION_KEY_LENGTH) + if(OPTION_KEY_LENGTH STREQUAL OPTION_LENGTH) + # no value for key provided, assume user wants to set option to "ON" + set(OPTION_VALUE "ON") + else() + math(EXPR OPTION_KEY_LENGTH "${OPTION_KEY_LENGTH}+1") + string(SUBSTRING "${OPTION}" "${OPTION_KEY_LENGTH}" "-1" OPTION_VALUE) + endif() + set(OPTION_KEY + "${OPTION_KEY}" + PARENT_SCOPE + ) + set(OPTION_VALUE + "${OPTION_VALUE}" + PARENT_SCOPE + ) +endfunction() + +# guesses the package version from a git tag +function(cpm_get_version_from_git_tag GIT_TAG RESULT) + string(LENGTH ${GIT_TAG} length) + if(length EQUAL 40) + # GIT_TAG is probably a git hash + set(${RESULT} + 0 + PARENT_SCOPE + ) + else() + string(REGEX MATCH "v?([0123456789.]*).*" _ ${GIT_TAG}) + set(${RESULT} + ${CMAKE_MATCH_1} + PARENT_SCOPE + ) + endif() +endfunction() + +# guesses if the git tag is a commit hash or an actual tag or a branch name. +function(cpm_is_git_tag_commit_hash GIT_TAG RESULT) + string(LENGTH "${GIT_TAG}" length) + # full hash has 40 characters, and short hash has at least 7 characters. + if(length LESS 7 OR length GREATER 40) + set(${RESULT} + 0 + PARENT_SCOPE + ) + else() + if(${GIT_TAG} MATCHES "^[a-fA-F0-9]+$") + set(${RESULT} + 1 + PARENT_SCOPE + ) + else() + set(${RESULT} + 0 + PARENT_SCOPE + ) + endif() + endif() +endfunction() + +function(cpm_prettify_package_arguments OUT_VAR IS_IN_COMMENT) + set(oneValueArgs + NAME + FORCE + VERSION + GIT_TAG + DOWNLOAD_ONLY + GITHUB_REPOSITORY + GITLAB_REPOSITORY + BITBUCKET_REPOSITORY + GIT_REPOSITORY + SOURCE_DIR + FIND_PACKAGE_ARGUMENTS + NO_CACHE + SYSTEM + GIT_SHALLOW + EXCLUDE_FROM_ALL + SOURCE_SUBDIR + ) + set(multiValueArgs URL OPTIONS DOWNLOAD_COMMAND) + cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + foreach(oneArgName ${oneValueArgs}) + if(DEFINED CPM_ARGS_${oneArgName}) + if(${IS_IN_COMMENT}) + string(APPEND PRETTY_OUT_VAR "#") + endif() + if(${oneArgName} STREQUAL "SOURCE_DIR") + string(REPLACE ${CMAKE_SOURCE_DIR} "\${CMAKE_SOURCE_DIR}" CPM_ARGS_${oneArgName} + ${CPM_ARGS_${oneArgName}} + ) + endif() + string(APPEND PRETTY_OUT_VAR " ${oneArgName} ${CPM_ARGS_${oneArgName}}\n") + endif() + endforeach() + foreach(multiArgName ${multiValueArgs}) + if(DEFINED CPM_ARGS_${multiArgName}) + if(${IS_IN_COMMENT}) + string(APPEND PRETTY_OUT_VAR "#") + endif() + string(APPEND PRETTY_OUT_VAR " ${multiArgName}\n") + foreach(singleOption ${CPM_ARGS_${multiArgName}}) + if(${IS_IN_COMMENT}) + string(APPEND PRETTY_OUT_VAR "#") + endif() + string(APPEND PRETTY_OUT_VAR " \"${singleOption}\"\n") + endforeach() + endif() + endforeach() + + if(NOT "${CPM_ARGS_UNPARSED_ARGUMENTS}" STREQUAL "") + if(${IS_IN_COMMENT}) + string(APPEND PRETTY_OUT_VAR "#") + endif() + string(APPEND PRETTY_OUT_VAR " ") + foreach(CPM_ARGS_UNPARSED_ARGUMENT ${CPM_ARGS_UNPARSED_ARGUMENTS}) + string(APPEND PRETTY_OUT_VAR " ${CPM_ARGS_UNPARSED_ARGUMENT}") + endforeach() + string(APPEND PRETTY_OUT_VAR "\n") + endif() + + set(${OUT_VAR} + ${PRETTY_OUT_VAR} + PARENT_SCOPE + ) + +endfunction() diff --git a/contrib/simdutf/cmake/JoinPaths.cmake b/contrib/simdutf/cmake/JoinPaths.cmake new file mode 100644 index 000000000..07172d839 --- /dev/null +++ b/contrib/simdutf/cmake/JoinPaths.cmake @@ -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 Python’s 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() \ No newline at end of file diff --git a/contrib/simdutf/cmake/Toolchains/loongarch64-linux-gnu.cmake b/contrib/simdutf/cmake/Toolchains/loongarch64-linux-gnu.cmake new file mode 100644 index 000000000..cded3d305 --- /dev/null +++ b/contrib/simdutf/cmake/Toolchains/loongarch64-linux-gnu.cmake @@ -0,0 +1,4 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR loongarch64) + +set(CMAKE_CROSSCOMPILING_EMULATOR "qemu-loongarch64") diff --git a/contrib/simdutf/cmake/Toolchains/riscv64-linux-gnu.cmake b/contrib/simdutf/cmake/Toolchains/riscv64-linux-gnu.cmake new file mode 100644 index 000000000..ed58a2dba --- /dev/null +++ b/contrib/simdutf/cmake/Toolchains/riscv64-linux-gnu.cmake @@ -0,0 +1,4 @@ +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR riscv64) + +set(CMAKE_CROSSCOMPILING_EMULATOR "qemu-riscv64-static") diff --git a/contrib/simdutf/cmake/add_cpp_test.cmake b/contrib/simdutf/cmake/add_cpp_test.cmake new file mode 100644 index 000000000..ad57f6a6f --- /dev/null +++ b/contrib/simdutf/cmake/add_cpp_test.cmake @@ -0,0 +1,63 @@ +# Helper so we don't have to repeat ourselves so much +# Usage: add_cpp_test(testname [COMPILE_ONLY] [SOURCES a.cpp b.cpp ...] [LABELS acceptance per_implementation ...]) +# SOURCES defaults to testname.cpp if not specified. +function(add_cpp_test TEST_NAME) + # Parse arguments + cmake_parse_arguments(PARSE_ARGV 1 ARGS "COMPILE_ONLY;LIBRARY;WILL_FAIL" "" "SOURCES;LABELS;DEPENDENCY_OF") + if (NOT ARGS_SOURCES) + list(APPEND ARGS_SOURCES ${TEST_NAME}.cpp) + endif() + if (ARGS_COMPILE_ONLY) + list(APPEND ${ARGS_LABELS} compile_only) + endif() + if(SIMDUTF_SANITIZE) + add_compile_options(-fsanitize=address -fno-omit-frame-pointer -fno-sanitize-recover=all) + add_compile_definitions(ASAN_OPTIONS=detect_leaks=1) + endif() + # Add the compile target + if (ARGS_LIBRARY) + add_library(${TEST_NAME} STATIC ${ARGS_SOURCES}) + else(ARGS_LIBRARY) + add_executable(${TEST_NAME} ${ARGS_SOURCES}) + endif(ARGS_LIBRARY) + + # Add test + if (ARGS_COMPILE_ONLY OR ARGS_LIBRARY) + add_test( + NAME ${TEST_NAME} + COMMAND ${CMAKE_COMMAND} --build . --target ${TEST_NAME} --config $ + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + ) + set_target_properties(${TEST_NAME} PROPERTIES EXCLUDE_FROM_ALL TRUE EXCLUDE_FROM_DEFAULT_BUILD TRUE) + else() + if (CMAKE_CROSSCOMPILING_EMULATOR) + add_test(${TEST_NAME} ${CMAKE_CROSSCOMPILING_EMULATOR} ${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME}) + else() + add_test(${TEST_NAME} ${TEST_NAME}) + endif() + + # Add to