diff --git a/docs/mkdocs/docs/api/macros/json_use_simdutf.md b/docs/mkdocs/docs/api/macros/json_use_simdutf.md index 507a1009b..26c54225d 100644 --- a/docs/mkdocs/docs/api/macros/json_use_simdutf.md +++ b/docs/mkdocs/docs/api/macros/json_use_simdutf.md @@ -18,6 +18,13 @@ scalar path. When `JSON_USE_SIMDUTF` is defined you must make the `simdutf.h` header available on the include path and link the simdutf library. When it is not defined, no simdutf header is included and there is no dependency. +!!! note "Requires C++17" + + simdutf requires C++17 and its header rejects older standards with an `#!cpp #error`. The backend is therefore only + compiled in from C++17 on. In C++11 and C++14 the macro has no effect and the scalar validator is used, which + accepts and rejects exactly the same input -- only throughput differs. Setting the macro project-wide is therefore + safe even when some translation units are built with an older standard. + !!! warning "Define consistently" The macro selects between two definitions of the same inline validation function. It must therefore be defined diff --git a/include/nlohmann/detail/input/string_scan.hpp b/include/nlohmann/detail/input/string_scan.hpp index 63c74db85..dc5b07a54 100644 --- a/include/nlohmann/detail/input/string_scan.hpp +++ b/include/nlohmann/detail/input/string_scan.hpp @@ -12,17 +12,23 @@ #include // uint64_t #include // memcpy -#if defined(JSON_USE_SIMDUTF) - // Optional SIMD backend for bulk UTF-8 validation. This is an opt-in - // external dependency: nlohmann/json itself stays header-only and the C++11 - // scalar validator below is always available; defining JSON_USE_SIMDUTF - // additionally requires the simdutf headers on the include path and linking - // the simdutf library. See string_bulk_run(). +#include + +// Optional SIMD backend for bulk UTF-8 validation. This is an opt-in external +// dependency: nlohmann/json itself stays header-only and the C++11 scalar +// validator below is always available; defining JSON_USE_SIMDUTF additionally +// requires the simdutf headers on the include path and linking the simdutf +// library. See string_bulk_run(). +// +// simdutf.h itself requires C++17 - it rejects older standards with an #error - +// so the backend is only compiled in from C++17 on. Below that the macro has no +// effect and the scalar validator is used; it accepts and rejects exactly the +// same input, so only throughput differs. macro_scope.hpp is included above to +// have JSON_HAS_CPP_17 available for this test. +#if defined(JSON_USE_SIMDUTF) && defined(JSON_HAS_CPP_17) #include #endif -#include - // This file contains the byte-level string-scanning helpers used by the lexer's // contiguous fast path. They operate purely on raw bytes (no dependency on the // lexer's template parameters) so they are free functions, keeping the lexer @@ -174,7 +180,7 @@ inline std::size_t scalar_string_bulk_run(const unsigned char* data, std::size_t return pos; } -#if defined(JSON_USE_SIMDUTF) +#if defined(JSON_USE_SIMDUTF) && defined(JSON_HAS_CPP_17) // Index of the first quote/escape/control byte in [data, data+n) (non-ASCII // bytes are *not* stops here - the whole run is handed to simdutf), or n. inline std::size_t find_string_delimiter(const unsigned char* data, std::size_t n) noexcept @@ -221,7 +227,7 @@ inline std::size_t find_string_delimiter(const unsigned char* data, std::size_t // produces the precise diagnostic. Without it, the pure scalar path is used. inline std::size_t string_bulk_run(const unsigned char* data, std::size_t n) noexcept { -#if defined(JSON_USE_SIMDUTF) +#if defined(JSON_USE_SIMDUTF) && defined(JSON_HAS_CPP_17) const std::size_t run = find_string_delimiter(data, n); if (run != 0 && simdutf::validate_utf8(reinterpret_cast(data), run)) { diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index f5887ad73..ef4f9da56 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -8166,18 +8166,24 @@ NLOHMANN_JSON_NAMESPACE_END #include // uint64_t #include // memcpy -#if defined(JSON_USE_SIMDUTF) - // Optional SIMD backend for bulk UTF-8 validation. This is an opt-in - // external dependency: nlohmann/json itself stays header-only and the C++11 - // scalar validator below is always available; defining JSON_USE_SIMDUTF - // additionally requires the simdutf headers on the include path and linking - // the simdutf library. See string_bulk_run(). - #include -#endif - // #include +// Optional SIMD backend for bulk UTF-8 validation. This is an opt-in external +// dependency: nlohmann/json itself stays header-only and the C++11 scalar +// validator below is always available; defining JSON_USE_SIMDUTF additionally +// requires the simdutf headers on the include path and linking the simdutf +// library. See string_bulk_run(). +// +// simdutf.h itself requires C++17 - it rejects older standards with an #error - +// so the backend is only compiled in from C++17 on. Below that the macro has no +// effect and the scalar validator is used; it accepts and rejects exactly the +// same input, so only throughput differs. macro_scope.hpp is included above to +// have JSON_HAS_CPP_17 available for this test. +#if defined(JSON_USE_SIMDUTF) && defined(JSON_HAS_CPP_17) + #include +#endif + // This file contains the byte-level string-scanning helpers used by the lexer's // contiguous fast path. They operate purely on raw bytes (no dependency on the // lexer's template parameters) so they are free functions, keeping the lexer @@ -8329,7 +8335,7 @@ inline std::size_t scalar_string_bulk_run(const unsigned char* data, std::size_t return pos; } -#if defined(JSON_USE_SIMDUTF) +#if defined(JSON_USE_SIMDUTF) && defined(JSON_HAS_CPP_17) // Index of the first quote/escape/control byte in [data, data+n) (non-ASCII // bytes are *not* stops here - the whole run is handed to simdutf), or n. inline std::size_t find_string_delimiter(const unsigned char* data, std::size_t n) noexcept @@ -8376,7 +8382,7 @@ inline std::size_t find_string_delimiter(const unsigned char* data, std::size_t // produces the precise diagnostic. Without it, the pure scalar path is used. inline std::size_t string_bulk_run(const unsigned char* data, std::size_t n) noexcept { -#if defined(JSON_USE_SIMDUTF) +#if defined(JSON_USE_SIMDUTF) && defined(JSON_HAS_CPP_17) const std::size_t run = find_string_delimiter(data, n); if (run != 0 && simdutf::validate_utf8(reinterpret_cast(data), run)) {