mirror of
https://github.com/simdjson/simdjson
synced 2026-06-08 17:27:07 +00:00
349 lines
13 KiB
C++
349 lines
13 KiB
C++
#ifndef SIMDJSON_SRC_IMPLEMENTATION_CPP
|
|
#define SIMDJSON_SRC_IMPLEMENTATION_CPP
|
|
|
|
#include <base.h>
|
|
#include <simdjson/generic/dependencies.h>
|
|
#include <simdjson/implementation.h>
|
|
#include <internal/isadetection.h>
|
|
|
|
#include <initializer_list>
|
|
#include <type_traits>
|
|
|
|
namespace simdjson {
|
|
|
|
bool implementation::supported_by_runtime_system() const {
|
|
uint32_t required_instruction_sets = this->required_instruction_sets();
|
|
uint32_t supported_instruction_sets = internal::detect_supported_architectures();
|
|
return ((supported_instruction_sets & required_instruction_sets) == required_instruction_sets);
|
|
}
|
|
|
|
} // namespace simdjson
|
|
|
|
#define SIMDJSON_CONDITIONAL_INCLUDE
|
|
|
|
#if SIMDJSON_IMPLEMENTATION_ARM64
|
|
#include <simdjson/arm64/implementation.h>
|
|
namespace simdjson {
|
|
namespace internal {
|
|
static const arm64::implementation* get_arm64_singleton() {
|
|
static const arm64::implementation arm64_singleton{};
|
|
return &arm64_singleton;
|
|
}
|
|
} // namespace internal
|
|
} // namespace simdjson
|
|
#endif // SIMDJSON_IMPLEMENTATION_ARM64
|
|
|
|
#if SIMDJSON_IMPLEMENTATION_FALLBACK
|
|
#include <simdjson/fallback/implementation.h>
|
|
namespace simdjson {
|
|
namespace internal {
|
|
static const fallback::implementation* get_fallback_singleton() {
|
|
static const fallback::implementation fallback_singleton{};
|
|
return &fallback_singleton;
|
|
}
|
|
} // namespace internal
|
|
} // namespace simdjson
|
|
#endif // SIMDJSON_IMPLEMENTATION_FALLBACK
|
|
|
|
|
|
#if SIMDJSON_IMPLEMENTATION_HASWELL
|
|
#include <simdjson/haswell/implementation.h>
|
|
namespace simdjson {
|
|
namespace internal {
|
|
static const haswell::implementation* get_haswell_singleton() {
|
|
static const haswell::implementation haswell_singleton{};
|
|
return &haswell_singleton;
|
|
}
|
|
} // namespace internal
|
|
} // namespace simdjson
|
|
#endif
|
|
|
|
#if SIMDJSON_IMPLEMENTATION_ICELAKE
|
|
#include <simdjson/icelake/implementation.h>
|
|
namespace simdjson {
|
|
namespace internal {
|
|
static const icelake::implementation* get_icelake_singleton() {
|
|
static const icelake::implementation icelake_singleton{};
|
|
return &icelake_singleton;
|
|
}
|
|
} // namespace internal
|
|
} // namespace simdjson
|
|
#endif
|
|
|
|
#if SIMDJSON_IMPLEMENTATION_PPC64
|
|
#include <simdjson/ppc64/implementation.h>
|
|
namespace simdjson {
|
|
namespace internal {
|
|
static const ppc64::implementation* get_ppc64_singleton() {
|
|
static const ppc64::implementation ppc64_singleton{};
|
|
return &ppc64_singleton;
|
|
}
|
|
} // namespace internal
|
|
} // namespace simdjson
|
|
#endif // SIMDJSON_IMPLEMENTATION_PPC64
|
|
|
|
#if SIMDJSON_IMPLEMENTATION_WESTMERE
|
|
#include <simdjson/westmere/implementation.h>
|
|
namespace simdjson {
|
|
namespace internal {
|
|
static const simdjson::westmere::implementation* get_westmere_singleton() {
|
|
static const simdjson::westmere::implementation westmere_singleton{};
|
|
return &westmere_singleton;
|
|
}
|
|
} // namespace internal
|
|
} // namespace simdjson
|
|
#endif // SIMDJSON_IMPLEMENTATION_WESTMERE
|
|
|
|
#if SIMDJSON_IMPLEMENTATION_LASX
|
|
#include <simdjson/lasx/implementation.h>
|
|
namespace simdjson {
|
|
namespace internal {
|
|
static const simdjson::lasx::implementation* get_lasx_singleton() {
|
|
static const simdjson::lasx::implementation lasx_singleton{};
|
|
return &lasx_singleton;
|
|
}
|
|
} // namespace internal
|
|
} // namespace simdjson
|
|
#endif // SIMDJSON_IMPLEMENTATION_LASX
|
|
|
|
#if SIMDJSON_IMPLEMENTATION_LSX
|
|
#include <simdjson/lsx/implementation.h>
|
|
namespace simdjson {
|
|
namespace internal {
|
|
static const simdjson::lsx::implementation* get_lsx_singleton() {
|
|
static const simdjson::lsx::implementation lsx_singleton{};
|
|
return &lsx_singleton;
|
|
}
|
|
} // namespace internal
|
|
} // namespace simdjson
|
|
#endif // SIMDJSON_IMPLEMENTATION_LSX
|
|
|
|
#if SIMDJSON_IMPLEMENTATION_RVV_VLS
|
|
#include <simdjson/rvv-vls/implementation.h>
|
|
namespace simdjson {
|
|
namespace internal {
|
|
static const simdjson::rvv_vls::implementation* get_rvv_vls_singleton() {
|
|
static const simdjson::rvv_vls::implementation rvv_vls_singleton{};
|
|
return &rvv_vls_singleton;
|
|
}
|
|
} // namespace internal
|
|
} // namespace simdjson
|
|
#endif // SIMDJSON_IMPLEMENTATION_RVV_VLS
|
|
|
|
#undef SIMDJSON_CONDITIONAL_INCLUDE
|
|
|
|
namespace simdjson {
|
|
namespace internal {
|
|
|
|
// When there is a single implementation, we should not pay a price
|
|
// for dispatching to the best implementation. We should just use the
|
|
// one we have. This is a compile-time check.
|
|
#define SIMDJSON_SINGLE_IMPLEMENTATION (SIMDJSON_IMPLEMENTATION_ICELAKE \
|
|
+ SIMDJSON_IMPLEMENTATION_HASWELL + SIMDJSON_IMPLEMENTATION_WESTMERE \
|
|
+ SIMDJSON_IMPLEMENTATION_ARM64 + SIMDJSON_IMPLEMENTATION_PPC64 \
|
|
+ SIMDJSON_IMPLEMENTATION_LSX + SIMDJSON_IMPLEMENTATION_LASX \
|
|
+ SIMDJSON_IMPLEMENTATION_RVV_VLS + SIMDJSON_IMPLEMENTATION_FALLBACK == 1)
|
|
|
|
#if SIMDJSON_SINGLE_IMPLEMENTATION
|
|
simdjson_really_inline static const implementation* get_single_implementation() {
|
|
return
|
|
#if SIMDJSON_IMPLEMENTATION_ICELAKE
|
|
get_icelake_singleton();
|
|
#endif
|
|
#if SIMDJSON_IMPLEMENTATION_HASWELL
|
|
get_haswell_singleton();
|
|
#endif
|
|
#if SIMDJSON_IMPLEMENTATION_WESTMERE
|
|
get_westmere_singleton();
|
|
#endif
|
|
#if SIMDJSON_IMPLEMENTATION_ARM64
|
|
get_arm64_singleton();
|
|
#endif
|
|
#if SIMDJSON_IMPLEMENTATION_PPC64
|
|
get_ppc64_singleton();
|
|
#endif
|
|
#if SIMDJSON_IMPLEMENTATION_LSX
|
|
get_lsx_singleton();
|
|
#endif
|
|
#if SIMDJSON_IMPLEMENTATION_LASX
|
|
get_lasx_singleton();
|
|
#endif
|
|
#if SIMDJSON_IMPLEMENTATION_RVV_VLS
|
|
get_rvv_vls_singleton();
|
|
#endif
|
|
#if SIMDJSON_IMPLEMENTATION_FALLBACK
|
|
get_fallback_singleton();
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
// Static array of known implementations. We're hoping these get baked into the executable
|
|
// without requiring a static initializer.
|
|
|
|
/**
|
|
* @private Detects best supported implementation on first use, and sets it
|
|
*/
|
|
class detect_best_supported_implementation_on_first_use final : public implementation {
|
|
public:
|
|
std::string name() const noexcept final { return set_best()->name(); }
|
|
std::string description() const noexcept final { return set_best()->description(); }
|
|
uint32_t required_instruction_sets() const noexcept final { return set_best()->required_instruction_sets(); }
|
|
simdjson_warn_unused error_code create_dom_parser_implementation(
|
|
size_t capacity,
|
|
size_t max_length,
|
|
std::unique_ptr<internal::dom_parser_implementation>& dst
|
|
) const noexcept final {
|
|
return set_best()->create_dom_parser_implementation(capacity, max_length, dst);
|
|
}
|
|
simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final {
|
|
return set_best()->minify(buf, len, dst, dst_len);
|
|
}
|
|
simdjson_warn_unused bool validate_utf8(const char * buf, size_t len) const noexcept final override {
|
|
return set_best()->validate_utf8(buf, len);
|
|
}
|
|
simdjson_inline detect_best_supported_implementation_on_first_use() noexcept : implementation("best_supported_detector", "Detects the best supported implementation and sets it", 0) {}
|
|
private:
|
|
const implementation *set_best() const noexcept;
|
|
};
|
|
|
|
static_assert(std::is_trivially_destructible<detect_best_supported_implementation_on_first_use>::value, "detect_best_supported_implementation_on_first_use should be trivially destructible");
|
|
|
|
static const std::initializer_list<const implementation *>& get_available_implementation_pointers() {
|
|
static const std::initializer_list<const implementation *> available_implementation_pointers {
|
|
#if SIMDJSON_IMPLEMENTATION_ICELAKE
|
|
get_icelake_singleton(),
|
|
#endif
|
|
#if SIMDJSON_IMPLEMENTATION_HASWELL
|
|
get_haswell_singleton(),
|
|
#endif
|
|
#if SIMDJSON_IMPLEMENTATION_WESTMERE
|
|
get_westmere_singleton(),
|
|
#endif
|
|
#if SIMDJSON_IMPLEMENTATION_ARM64
|
|
get_arm64_singleton(),
|
|
#endif
|
|
#if SIMDJSON_IMPLEMENTATION_PPC64
|
|
get_ppc64_singleton(),
|
|
#endif
|
|
#if SIMDJSON_IMPLEMENTATION_LASX
|
|
get_lasx_singleton(),
|
|
#endif
|
|
#if SIMDJSON_IMPLEMENTATION_LSX
|
|
get_lsx_singleton(),
|
|
#endif
|
|
#if SIMDJSON_IMPLEMENTATION_RVV_VLS
|
|
get_rvv_vls_singleton(),
|
|
#endif
|
|
#if SIMDJSON_IMPLEMENTATION_FALLBACK
|
|
get_fallback_singleton(),
|
|
#endif
|
|
}; // available_implementation_pointers
|
|
return available_implementation_pointers;
|
|
}
|
|
|
|
// So we can return UNSUPPORTED_ARCHITECTURE from the parser when there is no support
|
|
class unsupported_implementation final : public implementation {
|
|
public:
|
|
simdjson_warn_unused error_code create_dom_parser_implementation(
|
|
size_t,
|
|
size_t,
|
|
std::unique_ptr<internal::dom_parser_implementation>&
|
|
) const noexcept final {
|
|
return UNSUPPORTED_ARCHITECTURE;
|
|
}
|
|
simdjson_warn_unused error_code minify(const uint8_t *, size_t, uint8_t *, size_t &) const noexcept final override {
|
|
return UNSUPPORTED_ARCHITECTURE;
|
|
}
|
|
simdjson_warn_unused bool validate_utf8(const char *, size_t) const noexcept final override {
|
|
return false; // Just refuse to validate. Given that we have a fallback implementation
|
|
// it seems unlikely that unsupported_implementation will ever be used. If it is used,
|
|
// then it will flag all strings as invalid. The alternative is to return an error_code
|
|
// from which the user has to figure out whether the string is valid UTF-8... which seems
|
|
// like a lot of work just to handle the very unlikely case that we have an unsupported
|
|
// implementation. And, when it does happen (that we have an unsupported implementation),
|
|
// what are the chances that the programmer has a fallback? Given that *we* provide the
|
|
// fallback, it implies that the programmer would need a fallback for our fallback.
|
|
}
|
|
unsupported_implementation() : implementation("unsupported", "Unsupported CPU (no detected SIMD instructions)", 0) {}
|
|
};
|
|
|
|
static_assert(std::is_trivially_destructible<unsupported_implementation>::value, "unsupported_singleton should be trivially destructible");
|
|
|
|
const unsupported_implementation* get_unsupported_singleton() {
|
|
static const unsupported_implementation unsupported_singleton{};
|
|
return &unsupported_singleton;
|
|
}
|
|
|
|
size_t available_implementation_list::size() const noexcept {
|
|
return internal::get_available_implementation_pointers().size();
|
|
}
|
|
const implementation * const *available_implementation_list::begin() const noexcept {
|
|
return internal::get_available_implementation_pointers().begin();
|
|
}
|
|
const implementation * const *available_implementation_list::end() const noexcept {
|
|
return internal::get_available_implementation_pointers().end();
|
|
}
|
|
const implementation *available_implementation_list::detect_best_supported() const noexcept {
|
|
// They are prelisted in priority order, so we just go down the list
|
|
uint32_t supported_instruction_sets = internal::detect_supported_architectures();
|
|
for (const implementation *impl : internal::get_available_implementation_pointers()) {
|
|
uint32_t required_instruction_sets = impl->required_instruction_sets();
|
|
if ((supported_instruction_sets & required_instruction_sets) == required_instruction_sets) { return impl; }
|
|
}
|
|
return get_unsupported_singleton(); // this should never happen?
|
|
}
|
|
|
|
const implementation *detect_best_supported_implementation_on_first_use::set_best() const noexcept {
|
|
SIMDJSON_PUSH_DISABLE_WARNINGS
|
|
SIMDJSON_DISABLE_DEPRECATED_WARNING // Disable CRT_SECURE warning on MSVC: manually verified this is safe
|
|
char *force_implementation_name = getenv("SIMDJSON_FORCE_IMPLEMENTATION");
|
|
SIMDJSON_POP_DISABLE_WARNINGS
|
|
|
|
if (force_implementation_name) {
|
|
auto force_implementation = get_available_implementations()[force_implementation_name];
|
|
if (force_implementation) {
|
|
return get_active_implementation() = force_implementation;
|
|
} else {
|
|
// Note: abort() and stderr usage within the library is forbidden.
|
|
return get_active_implementation() = get_unsupported_singleton();
|
|
}
|
|
}
|
|
return get_active_implementation() = get_available_implementations().detect_best_supported();
|
|
}
|
|
|
|
} // namespace internal
|
|
|
|
SIMDJSON_DLLIMPORTEXPORT const internal::available_implementation_list& get_available_implementations() {
|
|
static const internal::available_implementation_list available_implementations{};
|
|
return available_implementations;
|
|
}
|
|
|
|
SIMDJSON_DLLIMPORTEXPORT internal::atomic_ptr<const implementation>& get_active_implementation() {
|
|
#if SIMDJSON_SINGLE_IMPLEMENTATION
|
|
// We immediately select the only implementation we have, skipping the
|
|
// detect_best_supported_implementation_on_first_use_singleton.
|
|
static internal::atomic_ptr<const implementation> active_implementation{internal::get_single_implementation()};
|
|
return active_implementation;
|
|
#else
|
|
static const internal::detect_best_supported_implementation_on_first_use detect_best_supported_implementation_on_first_use_singleton;
|
|
static internal::atomic_ptr<const implementation> active_implementation{&detect_best_supported_implementation_on_first_use_singleton};
|
|
return active_implementation;
|
|
#endif
|
|
}
|
|
|
|
simdjson_warn_unused error_code minify(const char *buf, size_t len, char *dst, size_t &dst_len) noexcept {
|
|
return get_active_implementation()->minify(reinterpret_cast<const uint8_t *>(buf), len, reinterpret_cast<uint8_t *>(dst), dst_len);
|
|
}
|
|
simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) noexcept {
|
|
return get_active_implementation()->validate_utf8(buf, len);
|
|
}
|
|
const implementation * builtin_implementation() {
|
|
static const implementation * builtin_impl = get_available_implementations()[SIMDJSON_STRINGIFY(SIMDJSON_BUILTIN_IMPLEMENTATION)];
|
|
assert(builtin_impl);
|
|
return builtin_impl;
|
|
}
|
|
|
|
} // namespace simdjson
|
|
|
|
#endif // SIMDJSON_SRC_IMPLEMENTATION_CPP
|