JSON-SIMD

 view release on metacpan or  search on metacpan

simdjson.cpp  view on Meta::CPAN


template<typename T>
concept constructible_from_string_view = std::is_constructible_v<T, std::string_view>
                                        && !std::is_same_v<T, std::string_view>
                                        && std::is_default_constructible_v<T>;

template<typename M>
concept string_view_keyed_map = string_view_like<typename M::key_type>
              && requires(std::remove_cvref_t<M>& m, typename M::key_type sv, typename M::mapped_type v) {
    { m.emplace(sv, v) } -> std::same_as<std::pair<typename M::iterator, bool>>;
};

/// Check if T is a container that we can append to, including:
///   std::vector, std::deque, std::list, std::string, ...
template <typename T>
concept appendable_containers =
    (details::supports_emplace_back<T> || details::supports_emplace<T> ||
    details::supports_push_back<T> || details::supports_push<T> ||
    details::supports_add<T> || details::supports_append<T> ||
    details::supports_insert<T>) && !string_view_keyed_map<T>;

/// Insert into the container however possible
template <appendable_containers T, typename... Args>
constexpr decltype(auto) emplace_one(T &vec, Args &&...args) {
  if constexpr (details::supports_emplace_back<T>) {
    return vec.emplace_back(std::forward<Args>(args)...);
  } else if constexpr (details::supports_emplace<T>) {
    return vec.emplace(std::forward<Args>(args)...);
  } else if constexpr (details::supports_push_back<T>) {
    return vec.push_back(std::forward<Args>(args)...);
  } else if constexpr (details::supports_push<T>) {
    return vec.push(std::forward<Args>(args)...);
  } else if constexpr (details::supports_add<T>) {
    return vec.add(std::forward<Args>(args)...);
  } else if constexpr (details::supports_append<T>) {
    return vec.append(std::forward<Args>(args)...);
  } else if constexpr (details::supports_insert<T>) {
    return vec.insert(std::forward<Args>(args)...);
  } else if constexpr (details::supports_op_append<T> && sizeof...(Args) == 1) {
    return vec.operator+=(std::forward<Args>(args)...);
  } else {
    static_assert(!sizeof(T *),
                  "We don't know how to add things to this container");
  }
}

/// This checks if the container will return a reference to the newly added
/// element after an insert which for example `std::vector::emplace_back` does
/// since C++17; this will allow some optimizations.
template <typename T>
concept returns_reference = appendable_containers<T> && requires {
  typename std::remove_cvref_t<T>::reference;
  requires requires(typename std::remove_cvref_t<T>::value_type &&val, T obj) {
    {
      emplace_one(obj, std::move(val))
    } -> std::same_as<typename std::remove_cvref_t<T>::reference>;
  };
};

template <typename T>
concept smart_pointer = requires(std::remove_cvref_t<T> ptr) {
  // Check if T has a member type named element_type
  typename std::remove_cvref_t<T>::element_type;

  // Check if T has a get() member function
  {
    ptr.get()
  } -> std::same_as<typename std::remove_cvref_t<T>::element_type *>;

  // Check if T can be dereferenced
  { *ptr } -> std::same_as<typename std::remove_cvref_t<T>::element_type &>;
};

template <typename T>
concept optional_type = requires(std::remove_cvref_t<T> obj) {
  typename std::remove_cvref_t<T>::value_type;
  { obj.value() } -> std::same_as<typename std::remove_cvref_t<T>::value_type&>;
  requires requires(typename std::remove_cvref_t<T>::value_type &&val) {
    obj.emplace(std::move(val));
    obj = std::move(val);
    {
      obj.value_or(val)
    } -> std::convertible_to<typename std::remove_cvref_t<T>::value_type>;
  };
  { static_cast<bool>(obj) } -> std::same_as<bool>; // convertible to bool
};



} // namespace concepts
} // namespace simdjson
#endif // SIMDJSON_SUPPORTS_DESERIALIZATION
#endif // SIMDJSON_CONCEPTS_H
/* end file simdjson/concepts.h */

/**
 * @brief The top level simdjson namespace, containing everything the library provides.
 */
namespace simdjson {

SIMDJSON_PUSH_DISABLE_UNUSED_WARNINGS

/** The maximum document size supported by simdjson. */
constexpr size_t SIMDJSON_MAXSIZE_BYTES = 0xFFFFFFFF;

/**
 * The amount of padding needed in a buffer to parse JSON.
 *
 * The input buf should be readable up to buf + SIMDJSON_PADDING
 * this is a stopgap; there should be a better description of the
 * main loop and its behavior that abstracts over this
 * See https://github.com/simdjson/simdjson/issues/174
 */
constexpr size_t SIMDJSON_PADDING = 64;

/**
 * By default, simdjson supports this many nested objects and arrays.
 *
 * This is the default for parser::max_depth().
 */
constexpr size_t DEFAULT_MAX_DEPTH = 1024;

SIMDJSON_POP_DISABLE_UNUSED_WARNINGS

class implementation;
struct padded_string;
class padded_string_view;
enum class stage1_mode;

namespace internal {

template<typename T>
class atomic_ptr;
class dom_parser_implementation;
class escape_json_string;

simdjson.cpp  view on Meta::CPAN


  if (ebx & cpuid_avx512er_bit) {
    host_isa |= instruction_set::AVX512ER;
  }

  if (ebx & cpuid_avx512cd_bit) {
    host_isa |= instruction_set::AVX512CD;
  }

  if (ebx & cpuid_avx512bw_bit) {
    host_isa |= instruction_set::AVX512BW;
  }

  if (ebx & cpuid_avx512vl_bit) {
    host_isa |= instruction_set::AVX512VL;
  }

  if (ecx & cpuid_avx512vbmi2_bit) {
    host_isa |= instruction_set::AVX512VBMI2;
  }

  return host_isa;
}

#elif defined(__loongarch_sx) && !defined(__loongarch_asx)

static inline uint32_t detect_supported_architectures() {
  return instruction_set::LSX;
}

#elif defined(__loongarch_asx)

static inline uint32_t detect_supported_architectures() {
  return instruction_set::LASX;
}

#else // fallback


static inline uint32_t detect_supported_architectures() {
  return instruction_set::DEFAULT;
}


#endif // end SIMD extension detection code

} // namespace internal
} // namespace simdjson

#endif // SIMDJSON_INTERNAL_ISADETECTION_H
/* end file 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

/* defining SIMDJSON_CONDITIONAL_INCLUDE */
#define SIMDJSON_CONDITIONAL_INCLUDE

#if SIMDJSON_IMPLEMENTATION_ARM64
/* including simdjson/arm64/implementation.h: #include <simdjson/arm64/implementation.h> */
/* begin file simdjson/arm64/implementation.h */
#ifndef SIMDJSON_ARM64_IMPLEMENTATION_H
#define SIMDJSON_ARM64_IMPLEMENTATION_H

/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
/* amalgamation skipped (editor-only): #include "simdjson/base.h" */
/* amalgamation skipped (editor-only): #include "simdjson/implementation.h" */
/* amalgamation skipped (editor-only): #include "simdjson/internal/instruction_set.h" */
/* amalgamation skipped (editor-only): #endif // SIMDJSON_CONDITIONAL_INCLUDE */

namespace simdjson {
namespace arm64 {

/**
 * @private
 */
class implementation final : public simdjson::implementation {
public:
  simdjson_inline implementation() : simdjson::implementation("arm64", "ARM NEON", internal::instruction_set::NEON) {}
  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;
  simdjson_warn_unused error_code minify(const uint8_t *buf, size_t len, uint8_t *dst, size_t &dst_len) const noexcept final;
  simdjson_warn_unused bool validate_utf8(const char *buf, size_t len) const noexcept final;
};

} // namespace arm64
} // namespace simdjson

#endif // SIMDJSON_ARM64_IMPLEMENTATION_H
/* end file 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
/* including simdjson/fallback/implementation.h: #include <simdjson/fallback/implementation.h> */
/* begin file simdjson/fallback/implementation.h */
#ifndef SIMDJSON_FALLBACK_IMPLEMENTATION_H
#define SIMDJSON_FALLBACK_IMPLEMENTATION_H

/* amalgamation skipped (editor-only): #ifndef SIMDJSON_CONDITIONAL_INCLUDE */
/* amalgamation skipped (editor-only): #include "simdjson/fallback/base.h" */

simdjson.cpp  view on Meta::CPAN

#if SIMDJSON_IMPLEMENTATION_LSX
    get_lsx_singleton(),
#endif
#if SIMDJSON_IMPLEMENTATION_LASX
    get_lasx_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
/* end file implementation.cpp */

/* defining SIMDJSON_CONDITIONAL_INCLUDE */



( run in 2.746 seconds using v1.01-cache-2.11-cpan-e1769b4cff6 )